From 58c26301bf432e334ec0dcea53a67ea304232145 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 18 Sep 2022 21:01:32 -0600 Subject: [PATCH 1/9] make ClientLocation Clone-able --- Cargo.toml | 4 + src/lib.rs | 2 + src/ship/items/actions.rs | 2 - src/ship/location.rs | 477 ++++++++++------- src/ship/packet/builder/lobby.rs | 50 +- src/ship/packet/builder/room.rs | 28 +- src/ship/packet/handler/communication.rs | 20 +- src/ship/packet/handler/direct_message.rs | 68 +-- src/ship/packet/handler/lobby.rs | 66 +-- src/ship/packet/handler/message.rs | 56 +- src/ship/packet/handler/quest.rs | 32 +- src/ship/packet/handler/room.rs | 109 ++-- src/ship/packet/handler/trade.rs | 620 +++++++++++----------- src/ship/ship.rs | 66 +-- src/ship/trade.rs | 24 +- tests/test_trade.rs | 37 +- 16 files changed, 891 insertions(+), 770 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fb618d9..0dc9c0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,3 +34,7 @@ strum = "0.19.5" strum_macros = "0.19" anyhow = { version = "1.0.47", features = ["backtrace"] } fix-hidden-lifetime-bug = "0.2.4" + + +[patch."http://git.sharnoth.com/jake/libpso"] +libpso = { path = "../libpso" } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 66c081f..47c688a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,8 @@ #![feature(drain_filter)] #![feature(try_blocks)] #![feature(once_cell)] +#![feature(pin_macro)] + extern crate fix_hidden_lifetime_bug; diff --git a/src/ship/items/actions.rs b/src/ship/items/actions.rs index c2213b5..8d4b2ba 100644 --- a/src/ship/items/actions.rs +++ b/src/ship/items/actions.rs @@ -575,7 +575,6 @@ where move |(item_state, transaction), arg| { let input = input.clone(); let func = func.clone(); - println!("i {:?} {:?}", input, arg); Box::pin(async move { let (state, result) = iterate_inner((item_state, transaction), input, func, arg.clone()).await?; Ok((state, result)) @@ -622,7 +621,6 @@ where T: Clone + Send + Sync, { move |(item_state, transaction), items| { - println!("fe {:?}", items); let func = func.clone(); Box::pin(async move { let (state, result) = foreach_inner((item_state, transaction), items, func).await?; diff --git a/src/ship/location.rs b/src/ship/location.rs index f4a1433..3e3c388 100644 --- a/src/ship/location.rs +++ b/src/ship/location.rs @@ -4,6 +4,10 @@ use std::time::SystemTime; use thiserror::Error; use crate::common::serverstate::ClientId; +use async_std::sync::{Arc, RwLock}; +use futures::{stream, StreamExt}; +use std::pin::pin; + pub const MAX_ROOMS: usize = 128; pub enum AreaType { @@ -133,33 +137,48 @@ pub enum RoomLobby { Lobby(LobbyId), } +#[derive(Clone, Debug)] pub struct ClientLocation { - lobbies: [Lobby; 15], - rooms: [Option; MAX_ROOMS], - client_location: HashMap, + lobbies: [Arc>; 15], + rooms: [Option>>; MAX_ROOMS], + client_location: Arc>>, } impl Default for ClientLocation { fn default() -> ClientLocation { + //const RNONE: Option>> = None; + //const LINIT: Arc> = Arc::new(RwLock::new(Lobby([None; 12]))); ClientLocation { - lobbies: [Lobby([None; 12]); 15], - rooms: [None; MAX_ROOMS], - client_location: HashMap::new(), + //lobbies: [LINIT; 15], + lobbies: core::array::from_fn(|_| Arc::new(RwLock::new(Lobby([None; 12])))), + rooms: core::array::from_fn(|_| None), + //rooms: [RNONE; MAX_ROOMS], + client_location: Arc::new(RwLock::new(HashMap::new())), } } } impl ClientLocation { - pub fn add_client_to_lobby(&mut self, id: ClientId, lobby: LobbyId) -> Result<(), JoinLobbyError> { - let l = self.lobbies.get_mut(lobby.0).ok_or(JoinLobbyError::LobbyDoesNotExist)?; - if l.0.iter().filter(|c| c.is_none()).count() == 0 { - return Err(JoinLobbyError::LobbyFull); + pub async fn add_client_to_lobby(&self, id: ClientId, lobby_id: LobbyId) -> Result<(), JoinLobbyError> { + { + let lobby = self.lobbies + .get(lobby_id.0) + .ok_or(JoinLobbyError::LobbyDoesNotExist)? + .read() + .await; + if lobby.0.iter().all(|c| c.is_some()) { + return Err(JoinLobbyError::LobbyFull); + } } - self.remove_client_from_area(id); + self.remove_client_from_area(id).await; - let l = self.lobbies.get_mut(lobby.0).ok_or(JoinLobbyError::LobbyDoesNotExist)?; - let (index, empty_slot) = l.0.iter_mut() + let mut lobby = self.lobbies + .get(lobby_id.0) + .ok_or(JoinLobbyError::LobbyDoesNotExist)? + .write() + .await; + let (index, empty_slot) = lobby.0.iter_mut() .enumerate() .find(|(_, k)| k.is_none()) .ok_or(JoinLobbyError::LobbyFull)?; @@ -168,40 +187,45 @@ impl ClientLocation { local_client: LocalClientId(index), time_join: SystemTime::now(), }); - self.client_location.insert(id, RoomLobby::Lobby(lobby)); + self.client_location + .write() + .await + .insert(id, RoomLobby::Lobby(lobby_id)); Ok(()) } - pub fn add_client_to_next_available_lobby(&mut self, id: ClientId, lobby: LobbyId) -> Result { - let l = (0..15) - .map(|lobby_index| { + pub async fn add_client_to_next_available_lobby(&self, id: ClientId, lobby: LobbyId) -> Result { + pin!(stream::iter(0..15) + .filter_map(|lobby_index| async move { let new_lobby = LobbyId((lobby.0 + lobby_index) % 15); - (new_lobby, self.add_client_to_lobby(id, new_lobby)) - }) - .find(|(_, lobby_option)| { - lobby_option.is_ok() - }) - .ok_or(JoinLobbyError::LobbyFull)?; - - Ok(l.0) + Some((new_lobby, self.add_client_to_lobby(id, new_lobby).await.ok()?)) + })) + .next() + .await + .map(|l| l.0) + .ok_or(JoinLobbyError::LobbyFull) } - pub fn create_new_room(&mut self, id: ClientId) -> Result { + pub async fn create_new_room(&mut self, id: ClientId) -> Result { let (index, empty_slot) = self.rooms.iter_mut() .enumerate() .find(|(_, r)| r.is_none()) .ok_or(CreateRoomError::NoOpenSlots)?; - *empty_slot = Some(Room([None; 4])); - self.add_client_to_room(id, RoomId(index)).map_err(|_err| CreateRoomError::JoinError)?; + *empty_slot = Some(Arc::new(RwLock::new(Room([None; 4])))); + self.add_client_to_room(id, RoomId(index)) + .await + .map_err(|_err| CreateRoomError::JoinError)?; Ok(RoomId(index)) } - pub fn add_client_to_room(&mut self, id: ClientId, room: RoomId) -> Result<(), JoinRoomError> { - let r = self.rooms.get_mut(room.0) + pub async fn add_client_to_room(&mut self, id: ClientId, room: RoomId) -> Result<(), JoinRoomError> { + let mut r = self.rooms.get(room.0) .ok_or(JoinRoomError::RoomDoesNotExist)? - .as_mut() - .ok_or(JoinRoomError::RoomDoesNotExist)?; + .as_ref() + .ok_or(JoinRoomError::RoomDoesNotExist)? + .write() + .await; let (index, empty_slot) = r.0.iter_mut() .enumerate() .find(|(_, k)| k.is_none()) @@ -211,38 +235,51 @@ impl ClientLocation { local_client: LocalClientId(index), time_join: SystemTime::now(), }); - self.remove_client_from_area(id); - self.client_location.insert(id, RoomLobby::Room(room)); + self.remove_client_from_area(id).await; + self.client_location + .write() + .await + .insert(id, RoomLobby::Room(room)); Ok(()) } - pub fn get_all_clients_by_client(&self, id: ClientId) -> Result, GetNeighborError> { - let area = self.client_location.get(&id).ok_or(GetNeighborError::InvalidClient)?; + pub async fn get_all_clients_by_client(&self, id: ClientId) -> Result, GetNeighborError> { + let area = self.client_location + .read() + .await; + let area = area + .get(&id) + .ok_or(GetNeighborError::InvalidClient)?; match area { RoomLobby::Room(room) => { - Ok(self.get_clients_in_room(*room).map_err(|_| GetNeighborError::InvalidArea)? + Ok(self.get_clients_in_room(*room).await.map_err(|_| GetNeighborError::InvalidArea)? .into_iter() .collect()) }, RoomLobby::Lobby(lobby) => { - Ok(self.get_clients_in_lobby(*lobby).map_err(|_| GetNeighborError::InvalidArea)? + Ok(self.get_clients_in_lobby(*lobby).await.map_err(|_| GetNeighborError::InvalidArea)? .into_iter() .collect()) } } } - pub fn get_client_neighbors(&self, id: ClientId) -> Result, GetNeighborError> { - let area = self.client_location.get(&id).ok_or(GetNeighborError::InvalidClient)?; + pub async fn get_client_neighbors(&self, id: ClientId) -> Result, GetNeighborError> { + let area = self.client_location + .read() + .await; + let area = area + .get(&id) + .ok_or(GetNeighborError::InvalidClient)?; match area { RoomLobby::Room(room) => { - Ok(self.get_clients_in_room(*room).map_err(|_| GetNeighborError::InvalidArea)? + Ok(self.get_clients_in_room(*room).await.map_err(|_| GetNeighborError::InvalidArea)? .into_iter() .filter(|c| c.client != id) .collect()) }, RoomLobby::Lobby(lobby) => { - Ok(self.get_clients_in_lobby(*lobby).map_err(|_| GetNeighborError::InvalidArea)? + Ok(self.get_clients_in_lobby(*lobby).await.map_err(|_| GetNeighborError::InvalidArea)? .into_iter() .filter(|c| c.client != id) .collect()) @@ -250,51 +287,72 @@ impl ClientLocation { } } - pub fn get_room_leader(&self, room: RoomId) -> Result { - let mut r = self.rooms[room.0] + pub async fn get_room_leader(&self, room: RoomId) -> Result { + let r = self.rooms[room.0] .as_ref() .ok_or(GetLeaderError::InvalidArea)? - .0.iter().flatten() + .read() + .await; + let mut r = r + .0 + .iter() + .flatten() .collect::>(); r.sort_by_key(|k| k.time_join); - let c = r.get(0).ok_or(GetLeaderError::NoClientInArea)?; + let c = r.get(0) + .ok_or(GetLeaderError::NoClientInArea)?; Ok(**c) } - pub fn get_lobby_leader(&self, lobby: LobbyId) -> Result { - let mut l = self.lobbies[lobby.0] - .0.iter().flatten() + pub async fn get_lobby_leader(&self, lobby: LobbyId) -> Result { + let l = self.lobbies[lobby.0] + .read() + .await; + let mut l = l + .0 + .iter() + .flatten() .collect::>(); l.sort_by_key(|k| k.time_join); let c = l.get(0).ok_or(GetLeaderError::NoClientInArea)?; Ok(**c) } - pub fn get_area_leader(&self, roomlobby: RoomLobby) -> Result { + pub async fn get_area_leader(&self, roomlobby: RoomLobby) -> Result { match roomlobby { RoomLobby::Room(room) => { - self.get_room_leader(room) + self.get_room_leader(room).await }, RoomLobby::Lobby(lobby) => { - self.get_lobby_leader(lobby) + self.get_lobby_leader(lobby).await } } } - pub fn get_leader_by_client(&self, id: ClientId) -> Result { - let area = self.client_location.get(&id).ok_or(GetLeaderError::InvalidClient)?; + pub async fn get_leader_by_client(&self, id: ClientId) -> Result { + let area = self.client_location + .read() + .await; + let area = area + .get(&id) + .ok_or(GetLeaderError::InvalidClient)?; match area { RoomLobby::Room(room) => { - self.get_room_leader(*room) + self.get_room_leader(*room).await }, RoomLobby::Lobby(lobby) => { - self.get_lobby_leader(*lobby) + self.get_lobby_leader(*lobby).await } } } - pub fn get_clients_in_lobby(&self, lobby: LobbyId) -> Result, GetClientsError> { - Ok(self.lobbies.get(lobby.0).ok_or(GetClientsError::InvalidArea)?.0 + pub async fn get_clients_in_lobby(&self, lobby: LobbyId) -> Result, GetClientsError> { + Ok(self.lobbies + .get(lobby.0) + .ok_or(GetClientsError::InvalidArea)? + .read() + .await + .0 .iter() .filter_map(|client| { client.map(|c| { @@ -303,10 +361,14 @@ impl ClientLocation { }).collect()) } - pub fn get_clients_in_room(&self, room: RoomId) -> Result, GetClientsError> { + pub async fn get_clients_in_room(&self, room: RoomId) -> Result, GetClientsError> { Ok(self.rooms.get(room.0) .ok_or(GetClientsError::InvalidArea)? - .ok_or(GetClientsError::InvalidArea)?.0 + .as_ref() + .ok_or(GetClientsError::InvalidArea)? + .read() + .await + .0 .iter() .filter_map(|client| { client.map(|c| { @@ -315,17 +377,26 @@ impl ClientLocation { }).collect()) } - pub fn get_local_client(&self, id: ClientId) -> Result { - let area = self.client_location.get(&id).ok_or(GetClientsError::InvalidClient)?; + pub async fn get_local_client(&self, id: ClientId) -> Result { + let area = self.client_location + .read() + .await; + let area = area + .get(&id) + .ok_or(GetClientsError::InvalidClient)?; match area { RoomLobby::Room(room) => { - self.get_clients_in_room(*room).map_err(|_| GetClientsError::InvalidArea)? + self.get_clients_in_room(*room) + .await + .map_err(|_| GetClientsError::InvalidArea)? .into_iter() .find(|c| c.client == id) .ok_or(GetClientsError::InvalidClient) }, RoomLobby::Lobby(lobby) => { - self.get_clients_in_lobby(*lobby).map_err(|_| GetClientsError::InvalidArea)? + self.get_clients_in_lobby(*lobby) + .await + .map_err(|_| GetClientsError::InvalidArea)? .into_iter() .find(|c| c.client == id) .ok_or(GetClientsError::InvalidClient) @@ -333,14 +404,17 @@ impl ClientLocation { } } - pub fn get_area(&self, id: ClientId) -> Result { - self.client_location.get(&id) + pub async fn get_area(&self, id: ClientId) -> Result { + self.client_location + .read() + .await + .get(&id) .ok_or(GetAreaError::InvalidClient) .map(Clone::clone) } - pub fn get_room(&self, id: ClientId) -> Result { - if let RoomLobby::Room(room) = self.client_location.get(&id).ok_or(GetAreaError::InvalidClient)? { + pub async fn get_room(&self, id: ClientId) -> Result { + if let RoomLobby::Room(room) = self.client_location.read().await.get(&id).ok_or(GetAreaError::InvalidClient)? { Ok(*room) } else { @@ -348,8 +422,8 @@ impl ClientLocation { } } - pub fn get_lobby(&self, id: ClientId) -> Result { - if let RoomLobby::Lobby(lobby) = self.client_location.get(&id).ok_or(GetAreaError::InvalidClient)? { + pub async fn get_lobby(&self, id: ClientId) -> Result { + if let RoomLobby::Lobby(lobby) = self.client_location.read().await.get(&id).ok_or(GetAreaError::InvalidClient)? { Ok(*lobby) } else { @@ -357,31 +431,41 @@ impl ClientLocation { } } - pub fn remove_client_from_area(&mut self, id: ClientId) -> Result<(), ClientRemovalError> { - let area = self.client_location.get_mut(&id).ok_or(ClientRemovalError::ClientNotInArea)?; - let client_list = match area { - RoomLobby::Room(room) => { - self.rooms[room.0] - .as_mut() - .map(|r| { - r.0.iter_mut() + pub async fn remove_client_from_area(&self, id: ClientId) -> Result<(), ClientRemovalError> { + fn remove_client(id: ClientId, client_list : &mut [Option; N]) { + client_list + .iter_mut() + .filter(|client| { + client.map_or(false, |c| { + c.client == id }) + }) + .for_each(|client| { + *client = None + }); + } + + let area = self.client_location + .read() + .await; + let area = area + .get(&id) + .ok_or(ClientRemovalError::ClientNotInArea)?; + match area { + RoomLobby::Room(room) => { + let r = self.rooms.get(room.0).ok_or(ClientRemovalError::InvalidArea)?; + if let Some(r) = r { + remove_client(id, &mut r.write().await.0) + } + else { + return Err(ClientRemovalError::InvalidArea) + } }, RoomLobby::Lobby(lobby) => { - Some(self.lobbies[lobby.0].0.iter_mut()) + remove_client(id, &mut self.lobbies[lobby.0].write().await.0) } }; - client_list - .ok_or(ClientRemovalError::InvalidArea)? - .filter(|client| { - client.map_or(false, |c| { - c.client == id - }) - }) - .for_each(|client| { - *client = None - }); Ok(()) } } @@ -397,173 +481,174 @@ impl ClientLocation { mod test { use super::*; - #[test] - fn test_add_client_to_lobby() { - let mut cl = ClientLocation::default(); - cl.add_client_to_lobby(ClientId(12), LobbyId(0)); - cl.add_client_to_lobby(ClientId(13), LobbyId(1)); - cl.add_client_to_lobby(ClientId(14), LobbyId(0)); + #[async_std::test] + async fn test_add_client_to_lobby() { + let cl = ClientLocation::default(); + cl.add_client_to_lobby(ClientId(12), LobbyId(0)).await.unwrap(); + cl.add_client_to_lobby(ClientId(13), LobbyId(1)).await.unwrap(); + cl.add_client_to_lobby(ClientId(14), LobbyId(0)).await.unwrap(); - assert!(cl.get_clients_in_lobby(LobbyId(0)).into_iter().flatten().map(|c| (c.client, c.local_client)).collect::>() == vec![ + assert!(cl.get_clients_in_lobby(LobbyId(0)).await.into_iter().flatten().map(|c| (c.client, c.local_client)).collect::>() == vec![ (ClientId(12), LocalClientId(0)), (ClientId(14), LocalClientId(1)), ]); } - #[test] - fn test_add_client_to_full_lobby() { - let mut cl = ClientLocation::default(); - (0..12).for_each(|i| { - cl.add_client_to_lobby(ClientId(i), LobbyId(0)); - }); - assert!(cl.add_client_to_lobby(ClientId(99), LobbyId(0)) == Err(JoinLobbyError::LobbyFull)); + #[async_std::test] + async fn test_add_client_to_full_lobby() { + let cl = ClientLocation::default(); + for i in 0..12 { + cl.add_client_to_lobby(ClientId(i), LobbyId(0)).await.unwrap(); + } + assert!(cl.add_client_to_lobby(ClientId(99), LobbyId(0)).await == Err(JoinLobbyError::LobbyFull)); } - #[test] - fn test_add_client_to_next_available_lobby() { - let mut cl = ClientLocation::default(); - (1..4).for_each(|lobby| { - (0..12).for_each(|i| { - cl.add_client_to_lobby(ClientId(lobby*12+i), LobbyId(lobby)); - }); - }); - assert!(cl.add_client_to_next_available_lobby(ClientId(99), LobbyId(1)) == Ok(LobbyId(4))); + #[async_std::test] + async fn test_add_client_to_next_available_lobby() { + let cl = ClientLocation::default(); + for lobby in 1..4 { + for i in 0..12 { + cl.add_client_to_lobby(ClientId(lobby*12+i), LobbyId(lobby)).await.unwrap(); + } + } + assert!(cl.add_client_to_next_available_lobby(ClientId(99), LobbyId(1)).await == Ok(LobbyId(4))); } - #[test] - fn test_add_to_lobby_when_all_are_full() { - let mut cl = ClientLocation::default(); - (0..15).for_each(|lobby| { - (0..12).for_each(|i| { - cl.add_client_to_lobby(ClientId(lobby*12+i), LobbyId(lobby)); - }); - }); - assert!(cl.add_client_to_next_available_lobby(ClientId(99), LobbyId(1)) == Err(JoinLobbyError::LobbyFull)); + #[async_std::test] + async fn test_add_to_lobby_when_all_are_full() { + let cl = ClientLocation::default(); + for lobby in 0..15 { + for i in 0..12 { + cl.add_client_to_lobby(ClientId(lobby*12+i), LobbyId(lobby)).await.unwrap(); + } + } + assert_eq!(cl.add_client_to_next_available_lobby(ClientId(99), LobbyId(1)).await, Err(JoinLobbyError::LobbyFull)); } - #[test] - fn test_new_room() { + #[async_std::test] + async fn test_new_room() { let mut cl = ClientLocation::default(); - assert!(cl.create_new_room(ClientId(12)) == Ok(RoomId(0))); + assert!(cl.create_new_room(ClientId(12)).await == Ok(RoomId(0))); } - #[test] - fn test_add_client_to_room() { + #[async_std::test] + async fn test_add_client_to_room() { let mut cl = ClientLocation::default(); - let room = cl.create_new_room(ClientId(12)).unwrap(); - assert!(cl.add_client_to_room(ClientId(234), room) == Ok(())); - assert!(cl.get_clients_in_room(room).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ + let room = cl.create_new_room(ClientId(12)).await.unwrap(); + assert!(cl.add_client_to_room(ClientId(234), room).await == Ok(())); + assert!(cl.get_clients_in_room(room).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ (ClientId(12), LocalClientId(0)), (ClientId(234), LocalClientId(1)), ]); } - #[test] - fn test_no_new_room_slots() { + #[async_std::test] + async fn test_no_new_room_slots() { let mut cl = ClientLocation::default(); for i in 0..128 { - cl.create_new_room(ClientId(i)); + cl.create_new_room(ClientId(i)).await; } - assert!(cl.create_new_room(ClientId(234)) == Err(CreateRoomError::NoOpenSlots)); + assert!(cl.create_new_room(ClientId(234)).await == Err(CreateRoomError::NoOpenSlots)); } - #[test] - fn test_joining_full_room() { + #[async_std::test] + async fn test_joining_full_room() { let mut cl = ClientLocation::default(); - let room = cl.create_new_room(ClientId(0)).unwrap(); - assert!(cl.add_client_to_room(ClientId(1), room) == Ok(())); - assert!(cl.add_client_to_room(ClientId(2), room) == Ok(())); - assert!(cl.add_client_to_room(ClientId(3), room) == Ok(())); - assert!(cl.add_client_to_room(ClientId(234), room) == Err(JoinRoomError::RoomFull)); + let room = cl.create_new_room(ClientId(0)).await.unwrap(); + assert!(cl.add_client_to_room(ClientId(1), room).await == Ok(())); + assert!(cl.add_client_to_room(ClientId(2), room).await == Ok(())); + assert!(cl.add_client_to_room(ClientId(3), room).await == Ok(())); + assert!(cl.add_client_to_room(ClientId(234), room).await == Err(JoinRoomError::RoomFull)); } - #[test] - fn test_adding_client_to_room_removes_from_lobby() { + #[async_std::test] + async fn test_adding_client_to_room_removes_from_lobby() { let mut cl = ClientLocation::default(); - cl.add_client_to_lobby(ClientId(93), LobbyId(0)); - cl.add_client_to_lobby(ClientId(23), LobbyId(0)); - cl.add_client_to_lobby(ClientId(51), LobbyId(0)); - cl.add_client_to_lobby(ClientId(12), LobbyId(0)); + cl.add_client_to_lobby(ClientId(93), LobbyId(0)).await; + cl.add_client_to_lobby(ClientId(23), LobbyId(0)).await; + cl.add_client_to_lobby(ClientId(51), LobbyId(0)).await; + cl.add_client_to_lobby(ClientId(12), LobbyId(0)).await; - let room = cl.create_new_room(ClientId(51)).unwrap(); - assert!(cl.add_client_to_room(ClientId(93), room) == Ok(())); - assert!(cl.get_clients_in_lobby(LobbyId(0)).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ + let room = cl.create_new_room(ClientId(51)).await.unwrap(); + assert!(cl.add_client_to_room(ClientId(93), room).await == Ok(())); + assert!(cl.get_clients_in_lobby(LobbyId(0)).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ (ClientId(23), LocalClientId(1)), (ClientId(12), LocalClientId(3)), ]); - assert!(cl.get_clients_in_room(room).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ + assert!(cl.get_clients_in_room(room).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ (ClientId(51), LocalClientId(0)), (ClientId(93), LocalClientId(1)), ]); } - #[test] - fn test_getting_neighbors() { - let mut cl = ClientLocation::default(); - cl.add_client_to_lobby(ClientId(93), LobbyId(0)); - cl.add_client_to_lobby(ClientId(23), LobbyId(0)); - cl.add_client_to_lobby(ClientId(51), LobbyId(0)); - cl.add_client_to_lobby(ClientId(12), LobbyId(0)); + #[async_std::test] + async fn test_getting_neighbors() { + let cl = ClientLocation::default(); + cl.add_client_to_lobby(ClientId(93), LobbyId(0)).await.unwrap(); + cl.add_client_to_lobby(ClientId(23), LobbyId(0)).await.unwrap(); + cl.add_client_to_lobby(ClientId(51), LobbyId(0)).await.unwrap(); + cl.add_client_to_lobby(ClientId(12), LobbyId(0)).await.unwrap(); - assert!(cl.get_client_neighbors(ClientId(23)).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ + assert!(cl.get_client_neighbors(ClientId(23)).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ (ClientId(93), LocalClientId(0)), (ClientId(51), LocalClientId(2)), (ClientId(12), LocalClientId(3)), ]); } - #[test] - fn test_failing_to_join_lobby_does_not_remove_from_current_area() { - let mut cl = ClientLocation::default(); - (0..12).for_each(|i| { - cl.add_client_to_lobby(ClientId(i), LobbyId(0)); - }); - cl.add_client_to_lobby(ClientId(99), LobbyId(1)); - cl.add_client_to_lobby(ClientId(99), LobbyId(0)); - assert!(cl.get_clients_in_lobby(LobbyId(0)).unwrap().len() == 12); - assert!(cl.get_clients_in_lobby(LobbyId(1)).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ - (ClientId(99), LocalClientId(0)), - ]); + #[async_std::test] + async fn test_failing_to_join_lobby_does_not_remove_from_current_area() { + let cl = ClientLocation::default(); + for i in 0..12 { + cl.add_client_to_lobby(ClientId(i), LobbyId(0)).await.unwrap(); + } + assert!(cl.add_client_to_lobby(ClientId(99), LobbyId(1)).await.is_ok()); + assert!(cl.add_client_to_lobby(ClientId(99), LobbyId(0)).await.is_err()); + assert_eq!(cl.get_clients_in_lobby(LobbyId(0)).await.unwrap().len(), 12); + assert_eq!( + cl.get_clients_in_lobby(LobbyId(1)).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>(), + vec![(ClientId(99), LocalClientId(0))] + ); } - #[test] - fn test_get_leader() { - let mut cl = ClientLocation::default(); - cl.add_client_to_lobby(ClientId(93), LobbyId(0)); - cl.add_client_to_lobby(ClientId(23), LobbyId(0)); - cl.add_client_to_lobby(ClientId(51), LobbyId(0)); - cl.add_client_to_lobby(ClientId(12), LobbyId(0)); + #[async_std::test] + async fn test_get_leader() { + let cl = ClientLocation::default(); + cl.add_client_to_lobby(ClientId(93), LobbyId(0)).await; + cl.add_client_to_lobby(ClientId(23), LobbyId(0)).await; + cl.add_client_to_lobby(ClientId(51), LobbyId(0)).await; + cl.add_client_to_lobby(ClientId(12), LobbyId(0)).await; - assert!(cl.get_leader_by_client(ClientId(51)).map(|c| (c.client, c.local_client)) == Ok((ClientId(93), LocalClientId(0)))); + assert!(cl.get_leader_by_client(ClientId(51)).await.map(|c| (c.client, c.local_client)) == Ok((ClientId(93), LocalClientId(0)))); } - #[test] - fn test_remove_client_from_room() { + #[async_std::test] + async fn test_remove_client_from_room() { let mut cl = ClientLocation::default(); - let room = cl.create_new_room(ClientId(51)).unwrap(); - cl.add_client_to_room(ClientId(93), room); - cl.add_client_to_room(ClientId(23), room); - cl.remove_client_from_area(ClientId(51)); - cl.add_client_to_room(ClientId(12), room); + let room = cl.create_new_room(ClientId(51)).await.unwrap(); + cl.add_client_to_room(ClientId(93), room).await; + cl.add_client_to_room(ClientId(23), room).await; + cl.remove_client_from_area(ClientId(51)).await; + cl.add_client_to_room(ClientId(12), room).await; - assert!(cl.get_clients_in_room(room).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ + assert!(cl.get_clients_in_room(room).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ (ClientId(12), LocalClientId(0)), (ClientId(93), LocalClientId(1)), (ClientId(23), LocalClientId(2)), ]); } - #[test] - fn test_leader_changes_on_leader_leaving() { + #[async_std::test] + async fn test_leader_changes_on_leader_leaving() { let mut cl = ClientLocation::default(); - let room = cl.create_new_room(ClientId(51)).unwrap(); - cl.add_client_to_room(ClientId(93), room); - cl.add_client_to_room(ClientId(23), room); - cl.remove_client_from_area(ClientId(51)); - cl.add_client_to_room(ClientId(12), room); - cl.remove_client_from_area(ClientId(23)); - cl.add_client_to_room(ClientId(99), room); + let room = cl.create_new_room(ClientId(51)).await.unwrap(); + cl.add_client_to_room(ClientId(93), room).await.unwrap(); + cl.add_client_to_room(ClientId(23), room).await.unwrap(); + cl.remove_client_from_area(ClientId(51)).await.unwrap(); + cl.add_client_to_room(ClientId(12), room).await.unwrap(); + cl.remove_client_from_area(ClientId(23)).await.unwrap(); + cl.add_client_to_room(ClientId(99), room).await.unwrap(); - assert!(cl.get_leader_by_client(ClientId(12)).map(|c| (c.client, c.local_client)) == Ok((ClientId(93), LocalClientId(1)))); + assert!(cl.get_leader_by_client(ClientId(12)).await.map(|c| (c.client, c.local_client)) == Ok((ClientId(93), LocalClientId(1)))); } } diff --git a/src/ship/packet/builder/lobby.rs b/src/ship/packet/builder/lobby.rs index 7126aba..a976f02 100644 --- a/src/ship/packet/builder/lobby.rs +++ b/src/ship/packet/builder/lobby.rs @@ -6,13 +6,13 @@ use crate::ship::packet::builder::{player_info}; use crate::ship::items::state::ItemState; -pub fn join_lobby(id: ClientId, - lobby: LobbyId, - client_location: &ClientLocation, - clients: &Clients, - item_state: &ItemState) - -> Result { - let lobby_clients = client_location.get_clients_in_lobby(lobby).map_err(|err| -> ClientLocationError { err.into() })?; +pub async fn join_lobby(id: ClientId, + lobby: LobbyId, + client_location: &ClientLocation, + clients: &Clients, + item_state: &ItemState) + -> Result { + let lobby_clients = client_location.get_clients_in_lobby(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?; let playerinfo = lobby_clients.iter() .map(|area_client| { let client = clients.get(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client)).unwrap(); @@ -20,8 +20,8 @@ pub fn join_lobby(id: ClientId, }); let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); - let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?; - let leader = client_location.get_lobby_leader(lobby).map_err(|err| -> ClientLocationError { err.into() })?; + let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let leader = client_location.get_lobby_leader(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?; Ok(JoinLobby { client: area_client.local_client.id(), leader: leader.local_client.id(), @@ -34,15 +34,15 @@ pub fn join_lobby(id: ClientId, }) } -pub fn add_to_lobby(id: ClientId, - lobby: LobbyId, - client_location: &ClientLocation, - clients: &Clients, - item_state: &ItemState) - -> Result { +pub async fn add_to_lobby(id: ClientId, + lobby: LobbyId, + client_location: &ClientLocation, + clients: &Clients, + item_state: &ItemState) + -> Result { let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); - let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?; - let leader = client_location.get_lobby_leader(lobby).map_err(|err| -> ClientLocationError { err.into() })?; + let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let leader = client_location.get_lobby_leader(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?; Ok(AddToLobby { flag: 1, client: area_client.local_client.id(), @@ -56,12 +56,16 @@ pub fn add_to_lobby(id: ClientId, }) } -pub fn remove_from_lobby(id: ClientId, - client_location: &ClientLocation) - -> Result { - let prev_area_index = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?.local_client.id(); - let prev_area_leader_index = client_location.get_area_leader(client_location.get_area(id) - .map_err(|err| -> ClientLocationError { err.into() })?) +pub async fn remove_from_lobby(id: ClientId, + client_location: &ClientLocation) + -> Result { + let prev_area_index = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?.local_client.id(); + let prev_area_leader_index = client_location + .get_area_leader(client_location + .get_area(id) + .await + .map_err(|err| -> ClientLocationError { err.into() })?) + .await .map_err(|err| -> ClientLocationError { err.into() })?.local_client.id(); Ok(LeaveLobby { client: prev_area_index, diff --git a/src/ship/packet/builder/room.rs b/src/ship/packet/builder/room.rs index 7e68077..6b55f21 100644 --- a/src/ship/packet/builder/room.rs +++ b/src/ship/packet/builder/room.rs @@ -7,26 +7,28 @@ use crate::ship::items::state::ItemState; use crate::ship::packet::builder::{player_header, player_info}; use std::convert::TryInto; -pub fn join_room(id: ClientId, - clients: &Clients, - client_location: &ClientLocation, - room_id: RoomId, - room: &RoomState) - -> Result { - let all_clients = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; - let players = all_clients.iter() +use futures::stream::StreamExt; + +pub async fn join_room(id: ClientId, + clients: &Clients, + client_location: &ClientLocation, + room_id: RoomId, + room: &RoomState) + -> Result { + let all_clients = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let players = futures::stream::iter(all_clients.iter()) .enumerate() - .fold(Ok([PlayerHeader::default(); 4]), |acc, (i, c)| -> Result<_, ShipError> { + .fold::, _, _>(Ok([PlayerHeader::default(); 4]), |acc, (i, c)| async move { let header_client = clients.get(&c.client).ok_or(ShipError::ClientNotFound(id))?; - let header_area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?; + let header_area_client = client_location.get_local_client(id).await.map_err(|err| ShipError::ClientLocationError(err.into()))?; acc.map(|mut a| { a[i] = player_header(0x10000, header_client, &header_area_client); a }) - })?; + }).await?; - let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?; - let leader = client_location.get_room_leader(room_id).map_err(|err| -> ClientLocationError { err.into() })?; + let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let leader = client_location.get_room_leader(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; Ok(JoinRoom { flag: all_clients.len() as u32, maps: room.maps.map_headers(), diff --git a/src/ship/packet/handler/communication.rs b/src/ship/packet/handler/communication.rs index c8942ec..6a83033 100644 --- a/src/ship/packet/handler/communication.rs +++ b/src/ship/packet/handler/communication.rs @@ -4,24 +4,24 @@ use crate::ship::ship::{SendShipPacket, ShipError, Clients}; use crate::ship::location::{ClientLocation}; use crate::entity::gateway::EntityGateway; -pub fn player_chat(id: ClientId, - msg: &PlayerChat, - client_location: &ClientLocation, - clients: &Clients) -> Result + Send>, ShipError> { +pub async fn player_chat(id: ClientId, + msg: &PlayerChat, + client_location: &ClientLocation, + clients: &Clients) -> Result + Send>, ShipError> { let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; let cmsg = PlayerChat::new(client.user.id.0, msg.message.clone()); - Ok(Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter() + Ok(Box::new(client_location.get_all_clients_by_client(id).await.unwrap().into_iter() .map(move |client| { (client.client, SendShipPacket::PlayerChat(cmsg.clone())) }))) } -pub fn request_infoboard(id: ClientId, - client_location: &ClientLocation, - clients: &Clients) - -> Box + Send> { - let area_clients = client_location.get_client_neighbors(id).unwrap(); +pub async fn request_infoboard(id: ClientId, + client_location: &ClientLocation, + clients: &Clients) + -> Box + Send> { + let area_clients = client_location.get_client_neighbors(id).await.unwrap(); let r = area_clients.iter() .filter_map(|c| { clients.get(&c.client) diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index ffa9693..4397ed5 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -34,21 +34,24 @@ pub enum MessageError { MismatchedTekIds(ClientItemId, ClientItemId), } -fn send_to_client(id: ClientId, target: u8, msg: DirectMessage, client_location: &ClientLocation) - -> Box + Send> { - Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter() +async fn send_to_client(id: ClientId, + target: u8, + msg: DirectMessage, + client_location: &ClientLocation) + -> Box + Send> { + Box::new(client_location.get_all_clients_by_client(id).await.unwrap().into_iter() .filter(move |client| client.local_client.id() == target) .map(move |client| { (client.client, SendShipPacket::DirectMessage(msg.clone())) })) } -pub fn guildcard_send(id: ClientId, - guildcard_send: &GuildcardSend, - target: u32, - client_location: &ClientLocation, - clients: &Clients) - -> Box + Send> { +pub async fn guildcard_send(id: ClientId, + guildcard_send: &GuildcardSend, + target: u32, + client_location: &ClientLocation, + clients: &Clients) + -> Box + Send> { let client = clients.get(&id).unwrap(); let msg = DirectMessage{ flag: target, @@ -65,7 +68,7 @@ pub fn guildcard_send(id: ClientId, class: client.character.char_class.into(), }), }; - send_to_client(id, target as u8, msg, client_location) + send_to_client(id, target as u8, msg, client_location).await } pub async fn request_item(id: ClientId, @@ -79,7 +82,7 @@ pub async fn request_item(id: ClientId, where EG: EntityGateway { - let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let room = rooms.get_mut(room_id.0) .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? .as_mut() @@ -90,7 +93,7 @@ where return Err(ShipError::MonsterAlreadyDroppedItem(id, request_item.enemy_id).into()) } - let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; + let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; let client_and_drop = clients_in_area.into_iter() .filter_map(|area_client| { @@ -129,9 +132,9 @@ where EG: EntityGateway { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?; - let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; - let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; + let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; let (item, floor_type) = item_state.get_floor_item(&client.character.id, &ClientItemId(pickup_item.item_id))?; let remove_item = builder::message::remove_item_from_floor(area_client, item)?; @@ -173,17 +176,17 @@ where } pub async fn request_box_item(id: ClientId, - box_drop_request: &BoxDropRequest, - mut entity_gateway: EG, - client_location: &ClientLocation, - clients: &mut Clients, - rooms: &mut Rooms, - item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + box_drop_request: &BoxDropRequest, + mut entity_gateway: EG, + client_location: &ClientLocation, + clients: &mut Clients, + rooms: &mut Rooms, + item_state: &mut ItemState) + -> Result + Send>, anyhow::Error> where -EG: EntityGateway + EG: EntityGateway { - let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let room = rooms.get_mut(room_id.0) .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? .as_mut() @@ -194,7 +197,7 @@ EG: EntityGateway return Err(ShipError::BoxAlreadyDroppedItem(id, box_drop_request.object_id).into()) } - let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; + let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; let client_and_drop = clients_in_area.into_iter() .filter_map(|area_client| { @@ -245,8 +248,8 @@ where EG: EntityGateway { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?; - let other_clients_in_area = client_location.get_all_clients_by_client(id).map_err(|err| -> ClientLocationError { err.into() })?; + let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let other_clients_in_area = client_location.get_all_clients_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let bank_action_pkts = match bank_interaction.action { BANK_ACTION_DEPOSIT => { if bank_interaction.item_id == 0xFFFFFFFF { @@ -294,7 +297,7 @@ pub async fn shop_request(id: ClientId, -> Result + Send>, anyhow::Error> { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let room = rooms.get(room_id.0) .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? .as_ref() @@ -335,7 +338,7 @@ where EG: EntityGateway { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?; + let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let (item, remove): (&(dyn ShopItem + Send + Sync), bool) = match buy_item.shop_type { SHOP_OPTION_WEAPON => { @@ -371,7 +374,7 @@ where } } - let other_clients_in_area = client_location.get_client_neighbors(id).map_err(|err| -> ClientLocationError { err.into() })?; + let other_clients_in_area = client_location.get_client_neighbors(id).await.map_err(|err| -> ClientLocationError { err.into() })?; Ok(Box::new(other_clients_in_area.into_iter() .map(move |c| { (c.client, SendShipPacket::Message(Message::new(GameMessage::CreateItem(create.clone())))) @@ -400,6 +403,7 @@ where { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; + // TODO: secids have different mod rates let (grind_mod, special_mod, percent_mod) = { let mut rng = rand::thread_rng(); @@ -443,7 +447,7 @@ where EG: EntityGateway { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?; + let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; if let Some((item_id, special_mod, percent_mod, grind_mod)) = client.tek { if item_id.0 != tek_accept.item_id { @@ -459,7 +463,7 @@ where let create_item_pkt = builder::message::create_individual_item(area_client, item_id, &weapon)?; - let neighbors = client_location.get_client_neighbors(id).map_err(|err| -> ClientLocationError { err.into() })?; + let neighbors = client_location.get_client_neighbors(id).await.map_err(|err| -> ClientLocationError { err.into() })?; Ok(Box::new(neighbors.into_iter() .map(move |c| { (c.client, SendShipPacket::Message(Message::new(GameMessage::CreateItem(create_item_pkt.clone())))) diff --git a/src/ship/packet/handler/lobby.rs b/src/ship/packet/handler/lobby.rs index 16483a9..3d133ad 100644 --- a/src/ship/packet/handler/lobby.rs +++ b/src/ship/packet/handler/lobby.rs @@ -46,16 +46,16 @@ pub fn block_selected(id: ClientId, ]) } -pub fn send_player_to_lobby(id: ClientId, - _pkt: &CharData, - client_location: &mut ClientLocation, - clients: &Clients, - item_state: &ItemState) - -> Result, anyhow::Error> { - let lobby = client_location.add_client_to_next_available_lobby(id, LobbyId(0)).map_err(|_| ShipError::TooManyClients)?; - let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_state)?; - let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state)?; - let neighbors = client_location.get_client_neighbors(id).unwrap(); +pub async fn send_player_to_lobby(id: ClientId, + _pkt: &CharData, + client_location: &mut ClientLocation, + clients: &Clients, + item_state: &ItemState) + -> Result, anyhow::Error> { + let lobby = client_location.add_client_to_next_available_lobby(id, LobbyId(0)).await.map_err(|_| ShipError::TooManyClients)?; + let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_state).await?; + let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state).await?; + let neighbors = client_location.get_client_neighbors(id).await.unwrap(); Ok(vec![(id, SendShipPacket::JoinLobby(join_lobby))] .into_iter() .chain(neighbors.into_iter() @@ -72,7 +72,7 @@ pub async fn change_lobby(id: ClientId, mut entity_gateway: EG) -> Result, anyhow::Error> { let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - let prev_area = client_location.get_area(id).map_err(|err| -> ClientLocationError {err.into()})?; + let prev_area = client_location.get_area(id).await.map_err(|err| -> ClientLocationError {err.into()})?; match prev_area { RoomLobby::Lobby(old_lobby) => { if old_lobby.0 == requested_lobby as usize { @@ -80,30 +80,30 @@ pub async fn change_lobby(id: ClientId, } }, RoomLobby::Room(old_room) => { - if client_location.get_client_neighbors(id)?.is_empty() { + if client_location.get_client_neighbors(id).await?.is_empty() { ship_rooms[old_room.0] = None; } item_state.remove_character_from_room(&client.character); }, } - let leave_lobby = packet::builder::lobby::remove_from_lobby(id, client_location)?; - let old_neighbors = client_location.get_client_neighbors(id).unwrap(); + let leave_lobby = packet::builder::lobby::remove_from_lobby(id, client_location).await?; + let old_neighbors = client_location.get_client_neighbors(id).await.unwrap(); let mut lobby = LobbyId(requested_lobby as usize); - if client_location.add_client_to_lobby(id, lobby).is_err() { + if client_location.add_client_to_lobby(id, lobby).await.is_err() { match prev_area { RoomLobby::Lobby(_lobby) => { let dialog = SmallDialog::new(String::from("Lobby is full.")); return Ok(vec![(id, SendShipPacket::SmallDialog(dialog))]) } RoomLobby::Room(_room) => { - lobby = client_location.add_client_to_next_available_lobby(id, lobby).map_err(|_| ShipError::TooManyClients)?; + lobby = client_location.add_client_to_next_available_lobby(id, lobby).await.map_err(|_| ShipError::TooManyClients)?; } } } item_state.load_character(&mut entity_gateway, &client.character).await?; - let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_state)?; - let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state)?; - let neighbors = client_location.get_client_neighbors(id).unwrap(); + let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_state).await?; + let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state).await?; + let neighbors = client_location.get_client_neighbors(id).await.unwrap(); Ok(vec![(id, SendShipPacket::JoinLobby(join_lobby))] .into_iter() .chain(neighbors.into_iter() @@ -113,30 +113,30 @@ pub async fn change_lobby(id: ClientId, .collect()) } -pub fn remove_from_lobby(id: ClientId, - client_location: &mut ClientLocation) - -> Result, anyhow::Error> { - let area_client = client_location.get_local_client(id)?; - let neighbors = client_location.get_client_neighbors(id)?; - let leader = client_location.get_leader_by_client(id)?; +pub async fn remove_from_lobby(id: ClientId, + client_location: &mut ClientLocation) + -> Result, anyhow::Error> { + let area_client = client_location.get_local_client(id).await?; + let neighbors = client_location.get_client_neighbors(id).await?; + let leader = client_location.get_leader_by_client(id).await?; let leave_lobby_pkt = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())); - client_location.remove_client_from_area(id)?; + client_location.remove_client_from_area(id).await?; Ok(neighbors.into_iter().map(|n| { (n.client, leave_lobby_pkt.clone()) }).collect()) } -pub fn get_room_tab_info(id: ClientId, - pkt: &MenuDetail, - client_location: &mut ClientLocation, - clients: &Clients, - rooms: &mut Rooms) - -> Result, anyhow::Error> { +pub async fn get_room_tab_info(id: ClientId, + pkt: &MenuDetail, + client_location: &mut ClientLocation, + clients: &Clients, + rooms: &mut Rooms) + -> Result, anyhow::Error> { let room_id = RoomId(pkt.item as usize); if let Some(_room) = rooms.get(pkt.item as usize).ok_or(ShipError::InvalidRoom(pkt.item))? { let mut room_info = String::new(); - let clients_in_room = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; + let clients_in_room = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; for client in clients_in_room { let cs = clients.get(&client.client).ok_or(ShipError::ClientNotFound(client.client))?; let gc = cs.user.guildcard; diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs index b76c46c..c738078 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -19,8 +19,8 @@ pub async fn request_exp(id: ClientId, rooms: &mut Rooms) -> Result + Send>, anyhow::Error> { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?; - let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let room = rooms.get_mut(room_id.0) .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? .as_mut() @@ -36,7 +36,7 @@ pub async fn request_exp(id: ClientId, ((monster_stats.exp as f32) * 0.8) as u32 }; - let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; + let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; let gain_exp_pkt = builder::message::character_gained_exp(area_client, exp_gain); let mut exp_pkts: Box + Send> = Box::new(clients_in_area.clone().into_iter() .map(move |c| { @@ -76,14 +76,14 @@ where EG: EntityGateway { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let room = rooms.get_mut(room_id.0) .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? .as_mut() .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; let area = room.map_areas.get_area_map(player_drop_item.map_area)?; drop_item(item_state, &mut entity_gateway, &client.character, &ClientItemId(player_drop_item.item_id), *area, (player_drop_item.x, player_drop_item.y, player_drop_item.z)).await?; - let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; + let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; let pdi = player_drop_item.clone(); Ok(Box::new(clients_in_area.into_iter() .map(move |c| { @@ -91,15 +91,15 @@ where }))) } -pub fn drop_coordinates(id: ClientId, - drop_coordinates: &DropCoordinates, - client_location: &ClientLocation, - clients: &mut Clients, - rooms: &Rooms) - -> Result + Send>, anyhow::Error> +pub async fn drop_coordinates(id: ClientId, + drop_coordinates: &DropCoordinates, + client_location: &ClientLocation, + clients: &mut Clients, + rooms: &Rooms) + -> Result + Send>, anyhow::Error> { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let room = rooms.get(room_id.0) .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? .as_ref() @@ -126,8 +126,8 @@ where EG: EntityGateway { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?; - let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; if let Some(drop_location) = client.item_drop_location { if drop_location.item_id.0 != no_longer_has_item.item_id { return Err(ShipError::DropInvalidItemId(no_longer_has_item.item_id).into()); @@ -140,7 +140,7 @@ where let no_longer_has_meseta_pkt = builder::message::player_no_longer_has_meseta(area_client, no_longer_has_item.amount as u32); client.item_drop_location = None; - let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; + let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; Ok(Box::new(clients_in_area.into_iter() .flat_map(move |c| { std::iter::once((c.client, SendShipPacket::Message(Message::new(GameMessage::DropSplitStack(dropped_meseta_pkt.clone()))))) @@ -163,7 +163,7 @@ where let dropped_item_pkt = builder::message::drop_split_stack(area_client, &dropped_item)?; client.item_drop_location = None; - let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; + let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; Ok(Box::new(clients_in_area.into_iter() .map(move |c| { (c.client, SendShipPacket::Message(Message::new(GameMessage::DropSplitStack(dropped_item_pkt.clone())))) @@ -171,7 +171,7 @@ where } } else if let Some(_tek) = client.tek { - let neighbors = client_location.get_client_neighbors(id).map_err(|err| -> ClientLocationError { err.into() })?; + let neighbors = client_location.get_client_neighbors(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let no_longer_has_item = no_longer_has_item.clone(); Ok(Box::new(neighbors.into_iter() .map(move |c| { @@ -183,14 +183,14 @@ where } } -pub fn update_player_position(id: ClientId, - message: &Message, - clients: &mut Clients, - client_location: &ClientLocation, - rooms: &Rooms) - -> Result + Send>, anyhow::Error> { +pub async fn update_player_position(id: ClientId, + message: &Message, + clients: &mut Clients, + client_location: &ClientLocation, + rooms: &Rooms) + -> Result + Send>, anyhow::Error> { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - if let Ok(room_id) = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() }) { + if let Ok(room_id) = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() }) { let room = rooms.get(room_id.0) .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? .as_ref() @@ -250,7 +250,7 @@ pub fn update_player_position(id: ClientId, } } else {} let m = message.clone(); - Ok(Box::new(client_location.get_client_neighbors(id).unwrap().into_iter() + Ok(Box::new(client_location.get_client_neighbors(id).await.unwrap().into_iter() .map(move |client| { (client.client, SendShipPacket::Message(m.clone())) }))) @@ -272,7 +272,7 @@ where take_meseta(item_state, &mut entity_gateway, &client.character.id, Meseta(charge.meseta)).await?; let charge = charge.clone(); - Ok(Box::new(client_location.get_client_neighbors(id).unwrap().into_iter() + Ok(Box::new(client_location.get_client_neighbors(id).await.unwrap().into_iter() .map(move |client| { (client.client, SendShipPacket::Message(Message::new(GameMessage::ChargeAttack(charge.clone())))) }))) @@ -308,7 +308,7 @@ where take_meseta(item_state, &mut entity_gateway, &client.character.id, Meseta(10)).await?; let pumc = pumc.clone(); - Ok(Box::new(client_location.get_client_neighbors(id).unwrap().into_iter() + Ok(Box::new(client_location.get_client_neighbors(id).await.unwrap().into_iter() .map(move |client| { (client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerUsedMedicalCenter(pumc.clone())))) }))) @@ -329,7 +329,7 @@ where feed_mag(item_state, &mut entity_gateway, &client.character, &ClientItemId(mag_feed.mag_id), &ClientItemId(mag_feed.item_id)).await?; let mag_feed = mag_feed.clone(); - Ok(Box::new(client_location.get_client_neighbors(id).unwrap().into_iter() + Ok(Box::new(client_location.get_client_neighbors(id).await.unwrap().into_iter() .map(move |client| { (client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerFeedMag(mag_feed.clone())))) }))) diff --git a/src/ship/packet/handler/quest.rs b/src/ship/packet/handler/quest.rs index c1c3f9f..7f97b7c 100644 --- a/src/ship/packet/handler/quest.rs +++ b/src/ship/packet/handler/quest.rs @@ -36,8 +36,8 @@ fn parse_filename(filename_bytes: &[u8; 16]) -> Result<(u16, u16, QuestFileType) } -pub fn send_quest_category_list(id: ClientId, rql: &RequestQuestList, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { - let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; +pub async fn send_quest_category_list(id: ClientId, rql: &RequestQuestList, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { + let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let room = rooms.get_mut(room_id.0) .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; @@ -46,8 +46,8 @@ pub fn send_quest_category_list(id: ClientId, rql: &RequestQuestList, client_loc Ok(Box::new(vec![(id, SendShipPacket::QuestCategoryList(qcl))].into_iter())) } -pub fn select_quest_category(id: ClientId, menuselect: &MenuSelect, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { - let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; +pub async fn select_quest_category(id: ClientId, menuselect: &MenuSelect, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { + let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let room = rooms.get_mut(room_id.0) .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; @@ -63,8 +63,8 @@ pub fn select_quest_category(id: ClientId, menuselect: &MenuSelect, client_locat } -pub fn quest_detail(id: ClientId, questdetailrequest: &QuestDetailRequest, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { - let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; +pub async fn quest_detail(id: ClientId, questdetailrequest: &QuestDetailRequest, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { + let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let room = rooms.get_mut(room_id.0) .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; @@ -82,9 +82,9 @@ pub fn quest_detail(id: ClientId, questdetailrequest: &QuestDetailRequest, clien Ok(Box::new(vec![(id, SendShipPacket::QuestDetail(qd))].into_iter())) } -pub fn player_chose_quest(id: ClientId, questmenuselect: &QuestMenuSelect, clients: &mut Clients, client_location: &ClientLocation, rooms: &mut Rooms) +pub async fn player_chose_quest(id: ClientId, questmenuselect: &QuestMenuSelect, clients: &mut Clients, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { - let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let room = rooms.get_mut(room_id.0) .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; @@ -103,7 +103,7 @@ pub fn player_chose_quest(id: ClientId, questmenuselect: &QuestMenuSelect, clien let bin = quest::quest_header(questmenuselect, &quest.bin_blob, "bin"); let dat = quest::quest_header(questmenuselect, &quest.dat_blob, "dat"); - let area_clients = client_location.get_all_clients_by_client(id).map_err(|err| -> ClientLocationError { err.into() })?; + let area_clients = client_location.get_all_clients_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; area_clients.iter().for_each(|c| { if let Some(client) = clients.get_mut(&c.client) { client.done_loading_quest = false; @@ -114,8 +114,8 @@ pub fn player_chose_quest(id: ClientId, questmenuselect: &QuestMenuSelect, clien }))) } -pub fn quest_file_request(id: ClientId, quest_file_request: &QuestFileRequest, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { - let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; +pub async fn quest_file_request(id: ClientId, quest_file_request: &QuestFileRequest, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { + let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let room = rooms.get_mut(room_id.0) .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; @@ -143,8 +143,8 @@ pub fn quest_file_request(id: ClientId, quest_file_request: &QuestFileRequest, c Ok(Box::new(vec![(id, SendShipPacket::QuestChunk(qc))].into_iter())) } -pub fn quest_chunk_ack(id: ClientId, quest_chunk_ack: &QuestChunkAck, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { - let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; +pub async fn quest_chunk_ack(id: ClientId, quest_chunk_ack: &QuestChunkAck, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { + let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let room = rooms.get_mut(room_id.0) .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; @@ -176,11 +176,11 @@ pub fn quest_chunk_ack(id: ClientId, quest_chunk_ack: &QuestChunkAck, client_loc Ok(Box::new(vec![(id, SendShipPacket::QuestChunk(qc))].into_iter())) } -pub fn done_loading_quest(id: ClientId, clients: &mut Clients, client_location: &ClientLocation) - -> Result + Send>, ShipError> { +pub async fn done_loading_quest(id: ClientId, clients: &mut Clients, client_location: &ClientLocation) + -> Result + Send>, ShipError> { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; client.done_loading_quest = true; - let area_clients = client_location.get_all_clients_by_client(id).map_err(|err| -> ClientLocationError { err.into() })?; + let area_clients = client_location.get_all_clients_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let all_loaded = area_clients.iter().all(|c| { clients.get(&c.client) .map(|client| { diff --git a/src/ship/packet/handler/room.rs b/src/ship/packet/handler/room.rs index a88203b..3a02102 100644 --- a/src/ship/packet/handler/room.rs +++ b/src/ship/packet/handler/room.rs @@ -8,14 +8,15 @@ use crate::ship::packet::builder; use crate::ship::room; use crate::ship::items::state::ItemState; use std::convert::{TryFrom}; +use futures::StreamExt; -pub fn create_room(id: ClientId, - create_room: &CreateRoom, - client_location: &mut ClientLocation, - clients: &mut Clients, - item_state: &mut ItemState, - rooms: &mut Rooms) - -> Result + Send>, anyhow::Error> { +pub async fn create_room(id: ClientId, + create_room: &CreateRoom, + client_location: &mut ClientLocation, + clients: &mut Clients, + item_state: &mut ItemState, + rooms: &mut Rooms) + -> Result + Send>, anyhow::Error> { let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; let level = LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp); match room::Difficulty::try_from(create_room.difficulty)? { @@ -37,22 +38,22 @@ pub fn create_room(id: ClientId, room::Difficulty::Normal => {}, }; - let area = client_location.get_area(id).unwrap(); - let area_client = client_location.get_local_client(id).unwrap(); - let lobby_neighbors = client_location.get_client_neighbors(id).unwrap(); - let room_id = client_location.create_new_room(id).unwrap(); + let area = client_location.get_area(id).await.unwrap(); + let area_client = client_location.get_local_client(id).await.unwrap(); + let lobby_neighbors = client_location.get_client_neighbors(id).await.unwrap(); + let room_id = client_location.create_new_room(id).await.unwrap(); let mut room = room::RoomState::from_create_room(create_room, client.character.section_id).unwrap(); room.bursting = true; item_state.add_character_to_room(room_id, &client.character, area_client); - let join_room = builder::room::join_room(id, clients, client_location, room_id, &room)?; + let join_room = builder::room::join_room(id, clients, client_location, room_id, &room).await?; rooms[room_id.0] = Some(room); let mut result: Box + Send> = Box::new( vec![(id, SendShipPacket::JoinRoom(join_room))].into_iter() ); - if let Ok(leader) = client_location.get_area_leader(area) { + if let Ok(leader) = client_location.get_area_leader(area).await { let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())); result = Box::new(result.chain(lobby_neighbors .into_iter() @@ -64,24 +65,24 @@ pub fn create_room(id: ClientId, Ok(result) } -pub fn room_name_request(id: ClientId, - client_location: &ClientLocation, - rooms: &Rooms) - -> Box + Send> { - let area = client_location.get_area(id).unwrap(); +pub async fn room_name_request(id: ClientId, + client_location: &ClientLocation, + rooms: &Rooms) + -> Box + Send> { + let area = client_location.get_area(id).await.unwrap(); match area { RoomLobby::Room(room) => Box::new(vec![(id, SendShipPacket::RoomNameResponse(RoomNameResponse {name: rooms[room.0].as_ref().unwrap().name.clone()}))].into_iter()), RoomLobby::Lobby(_) => panic!() } } -pub fn join_room(id: ClientId, - pkt: &MenuSelect, - client_location: &mut ClientLocation, - clients: &mut Clients, - item_state: &mut ItemState, - rooms: &mut Rooms) - -> Result + Send>, ShipError> { +pub async fn join_room(id: ClientId, + pkt: &MenuSelect, + client_location: &mut ClientLocation, + clients: &mut Clients, + item_state: &mut ItemState, + rooms: &mut Rooms) + -> Result + Send>, ShipError> { let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; let level = LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp); // let room = rooms.get(pkt.item as usize).ok_or(ShipError::InvalidRoom(pkt.item))?.as_ref().unwrap(); // clippy look what you made me do @@ -106,22 +107,22 @@ pub fn join_room(id: ClientId, _ => {}, }; - let original_area = client_location.get_area(id).unwrap(); - let original_neighbors = client_location.get_client_neighbors(id).unwrap(); + let original_area = client_location.get_area(id).await.unwrap(); + let original_neighbors = client_location.get_client_neighbors(id).await.unwrap(); if room.bursting { return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("player is bursting\nplease wait".into())))].into_iter())) } let room_id = RoomId(pkt.item as usize); - let original_room_clients = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; - client_location.add_client_to_room(id, room_id).unwrap(); // TODO: show room full error or whatever + let original_room_clients = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; + client_location.add_client_to_room(id, room_id).await.unwrap(); // TODO: show room full error or whatever let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?; + let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; item_state.add_character_to_room(room_id, &client.character, area_client); - let leader = client_location.get_room_leader(room_id).map_err(|err| -> ClientLocationError { err.into() })?; - let join_room = builder::room::join_room(id, clients, client_location, room_id, room)?; + let leader = client_location.get_room_leader(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let join_room = builder::room::join_room(id, clients, client_location, room_id, room).await?; let add_to = builder::room::add_to_room(id, client, &area_client, &leader, item_state, room_id)?; let room = rooms.get_mut(room_id.0).unwrap().as_mut().unwrap(); @@ -134,7 +135,7 @@ pub fn join_room(id: ClientId, .map(move |c| (c.client, SendShipPacket::AddToRoom(add_to.clone()))) )); - if let Ok(leader) = client_location.get_area_leader(original_area) { + if let Ok(leader) = client_location.get_area_leader(original_area).await { let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())); result = Box::new(result.chain(original_neighbors.into_iter() .map(move |c| (c.client, leave_lobby.clone())))) @@ -146,11 +147,11 @@ pub fn join_room(id: ClientId, } } -pub fn done_bursting(id: ClientId, - client_location: &ClientLocation, - rooms: &mut Rooms) - -> Box + Send> { - let area = client_location.get_area(id).unwrap(); +pub async fn done_bursting(id: ClientId, + client_location: &ClientLocation, + rooms: &mut Rooms) + -> Box + Send> { + let area = client_location.get_area(id).await.unwrap(); let mut rare_monster_list: Option> = None; if let RoomLobby::Room(room_id) = area { if let Some(room) = rooms.get_mut(room_id.0).unwrap().as_mut() { @@ -158,9 +159,9 @@ pub fn done_bursting(id: ClientId, rare_monster_list = Some(room.maps.get_rare_monster_list()); }; } - let area_client = client_location.get_local_client(id).unwrap(); // TODO: unwrap + let area_client = client_location.get_local_client(id).await.unwrap(); // TODO: unwrap let mut result: Box + Send> = Box::new( - client_location.get_client_neighbors(id).unwrap().into_iter() // TODO: unwrap + client_location.get_client_neighbors(id).await.unwrap().into_iter() // TODO: unwrap .flat_map(move |client| { vec![ (client.client, SendShipPacket::Message(Message::new(GameMessage::BurstDone(BurstDone { @@ -180,19 +181,19 @@ pub fn done_bursting(id: ClientId, result } -pub fn request_room_list(id: ClientId, - client_location: &ClientLocation, - rooms: &Rooms) - -> Box + Send> { - let active_room_list = rooms.iter() +pub async fn request_room_list(id: ClientId, + client_location: &ClientLocation, + rooms: &Rooms) + -> Box + Send> { + let active_room_list = futures::stream::iter(rooms.iter()) .enumerate() - .filter_map(|(i, r)| { - r.as_ref().map(|room| { + .filter_map(|(i, r)| async move { + r.as_ref().map(|room| async move { RoomList { menu_id: ROOM_MENU_ID, item_id: i as u32, difficulty: room.get_difficulty_for_room_list(), - players: client_location.get_clients_in_room(RoomId(i)).unwrap().len() as u8, + players: client_location.get_clients_in_room(RoomId(i)).await.unwrap().len() as u8, name: libpso::utf8_to_utf16_array!(room.name, 16), episode: room.get_episode_for_room_list(), flags: room.get_flags_for_room_list(), @@ -211,17 +212,17 @@ pub fn request_room_list(id: ClientId, Box::new(vec![(id, SendShipPacket::RoomListResponse(RoomListResponse { baseroom, - rooms: active_room_list.collect() + rooms: futures::future::join_all(active_room_list.collect::>().await).await }))].into_iter()) } -pub fn cool_62(id: ClientId, - cool_62: &Like62ButCooler, - client_location: &ClientLocation) - -> Box + Send> { +pub async fn cool_62(id: ClientId, + cool_62: &Like62ButCooler, + client_location: &ClientLocation) + -> Box + Send> { let target = cool_62.flag as u8; let cool_62 = cool_62.clone(); - Box::new(client_location.get_client_neighbors(id).unwrap().into_iter() + Box::new(client_location.get_client_neighbors(id).await.unwrap().into_iter() .filter(move |client| client.local_client.id() == target) .map(move |client| { (client.client, SendShipPacket::Like62ButCooler(cool_62.clone())) diff --git a/src/ship/packet/handler/trade.rs b/src/ship/packet/handler/trade.rs index 465b76d..8710d72 100644 --- a/src/ship/packet/handler/trade.rs +++ b/src/ship/packet/handler/trade.rs @@ -13,6 +13,7 @@ use crate::ship::packet::builder; use crate::ship::items::tasks::trade_items; use crate::ship::location::{AreaClient, RoomId}; use crate::entity::item::Meseta; +use crate::ship::trade::ClientTradeState; pub const MESETA_ITEM_ID: ClientItemId = ClientItemId(0xFFFFFF01); pub const OTHER_MESETA_ITEM_ID: ClientItemId = ClientItemId(0xFFFFFFFF); @@ -48,15 +49,47 @@ pub enum TradeError { } + +pub async fn do_trade_action(id: ClientId, + pkt: TradeRequest, + client_location: &ClientLocation, + target: u32, + this: &mut ClientTradeState, + other: &mut ClientTradeState, + action: F) -> Result + Send>, ShipError> +where + F: Fn(&mut ClientTradeState, &mut ClientTradeState) -> Result<(), ShipError>, +{ + Ok(match action(this, other) { + Ok(_) => { + Box::new(client_location.get_all_clients_by_client(id).await?.into_iter() + .filter(move |client| client.local_client.id() == target as u8) + .map(move |client| { + (client.client, SendShipPacket::DirectMessage(DirectMessage::new(target, GameMessage::TradeRequest(pkt.clone())))) + })) + }, + Err(_) => { + // TODO: some sort of error logging? + Box::new(client_location.get_all_clients_by_client(id).await?.into_iter() + .filter(move |client| client.local_client.id() == target as u8) + .map(move |client| { + (client.client, SendShipPacket::CancelTrade(CancelTrade {})) + }) + .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {}))))) + } + }) +} + + // TODO: remove target pub async fn trade_request(id: ClientId, - trade_request: &TradeRequest, - target: u32, - client_location: &ClientLocation, - clients: &mut Clients, - item_state: &mut ItemState, - trades: &mut TradeState) - -> Result + Send>, ShipError> + trade_request: &TradeRequest, + target: u32, + client_location: &ClientLocation, + clients: &mut Clients, + item_state: &mut ItemState, + trades: &mut TradeState) + -> Result + Send>, ShipError> { let trade_request = trade_request.clone(); // TODO: make this function take ownership of packet match trade_request.trade { @@ -66,7 +99,7 @@ pub async fn trade_request(id: ClientId, if trades.in_trade(&id) { return Err(TradeError::ClientAlreadyInTrade.into()) } - let trade_partner = client_location.get_client_neighbors(id)? + let trade_partner = client_location.get_client_neighbors(id).await? .into_iter() .find(|ac| { ac.local_client.id() == target as u8 //trade_request.client @@ -76,204 +109,155 @@ pub async fn trade_request(id: ClientId, return Err(TradeError::OtherAlreadyInTrade.into()) } trades.new_trade(&id, &trade_partner.client); - Ok(Box::new(client_location.get_all_clients_by_client(id)?.into_iter() + Ok(Box::new(client_location.get_all_clients_by_client(id).await?.into_iter() .filter(move |client| client.local_client.id() == target as u8) .map(move |client| { (client.client, SendShipPacket::DirectMessage(DirectMessage::new(target, GameMessage::TradeRequest(trade_request.clone())))) }))) }, TradeRequestInitializeCommand::Respond => { - Ok(trades - .with(&id, |this, other| -> Option + Send>> { - if this.status == TradeStatus::ReceivedRequest && other.status == TradeStatus::SentRequest { - this.status = TradeStatus::Trading; - other.status = TradeStatus::Trading; - - let trade_request = trade_request.clone(); - Some(Box::new(client_location.get_all_clients_by_client(id).ok()?.into_iter() - .filter(move |client| client.local_client.id() == target as u8) - .map(move |client| { - (client.client, SendShipPacket::DirectMessage(DirectMessage::new(target, GameMessage::TradeRequest(trade_request.clone())))) - }))) - } - else { - None - } - })? - .unwrap_or_else(|| -> Box + Send> { - trades.remove_trade(&id); - Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter() - .filter(move |client| client.local_client.id() == target as u8) - .map(move |client| { - (client.client, SendShipPacket::CancelTrade(CancelTrade {})) - }) - .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {}))))) - })) + trades + .with(&id, |mut this, mut other| { + let trade_request = trade_request.clone(); + async move { + do_trade_action(id, trade_request, client_location, target, &mut this, &mut other, |this, other| { + if this.status == TradeStatus::ReceivedRequest && other.status == TradeStatus::SentRequest { + this.status = TradeStatus::Trading; + other.status = TradeStatus::Trading; + Ok(()) + } + else { + Err(TradeError::MismatchedStatus.into()) + } + }).await + }}).await? } } }, TradeRequestCommand::AddItem(item_id, amount) => { - Ok(trades - .with(&id, |this, other| -> Result + Send>, anyhow::Error> { - if this.status == TradeStatus::Trading && other.status == TradeStatus::Trading { - let client = clients.get(&this.client()).ok_or_else(|| ShipError::ClientNotFound(this.client()))?; - let inventory = item_state.get_character_inventory(&client.character)?; - if ClientItemId(item_id) == MESETA_ITEM_ID { - this.meseta += amount as usize; - } - else { - let item = inventory.get_by_client_id(&ClientItemId(item_id)).ok_or(ItemStateError::InvalidItemId(ClientItemId(item_id)))?; - - match &item.item { - InventoryItemDetail::Individual(_) => { - this.items.push(TradeItem::Individual(ClientItemId(item_id))); - }, - InventoryItemDetail::Stacked(stacked_item) => { - if stacked_item.count() < amount as usize { - return Err(TradeError::InvalidStackAmount(ClientItemId(item_id), amount as usize).into()); + trades + .with(&id, |mut this, mut other| { + let trade_request = trade_request.clone(); + async move { + do_trade_action(id, trade_request, client_location, target, &mut this, &mut other, |this, other| { + if this.status == TradeStatus::Trading && other.status == TradeStatus::Trading { + let client = clients.get(&this.client()).ok_or_else(|| ShipError::ClientNotFound(this.client()))?; + let inventory = item_state.get_character_inventory(&client.character)?; + if ClientItemId(item_id) == MESETA_ITEM_ID { + this.meseta += amount as usize; + } + else { + let item = inventory.get_by_client_id(&ClientItemId(item_id)).ok_or(ItemStateError::InvalidItemId(ClientItemId(item_id)))?; + + match &item.item { + InventoryItemDetail::Individual(_) => { + this.items.push(TradeItem::Individual(ClientItemId(item_id))); + }, + InventoryItemDetail::Stacked(stacked_item) => { + if stacked_item.count() < amount as usize { + return Err(TradeError::InvalidStackAmount(ClientItemId(item_id), amount as usize).into()); + } + this.items.push(TradeItem::Stacked(ClientItemId(item_id), amount as usize)); + }, } - this.items.push(TradeItem::Stacked(ClientItemId(item_id), amount as usize)); - }, + } + Ok(()) } - } - - let trade_request = trade_request.clone(); - Ok(Box::new(client_location.get_all_clients_by_client(id)?.into_iter() - .filter(move |client| client.local_client.id() == target as u8) - .map(move |client| { - (client.client, SendShipPacket::DirectMessage(DirectMessage::new(target, GameMessage::TradeRequest(trade_request.clone())))) - }))) - } - else { - Err(TradeError::MismatchedStatus.into()) - } - })? - .unwrap_or_else(|_err| { - trades.remove_trade(&id); - Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter() - .filter(move |client| client.local_client.id() == target as u8) - .map(move |client| { - (client.client, SendShipPacket::CancelTrade(CancelTrade {})) - }) - .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {}))))) - })) + else { + Err(TradeError::MismatchedStatus.into()) + } + }).await + }}).await? }, TradeRequestCommand::RemoveItem(item_id, amount) => { - Ok(trades - .with(&id, |this, other| -> Option + Send>> { - if this.status == TradeStatus::Trading && other.status == TradeStatus::Trading { - let client = clients.get(&this.client())?; //.ok_or(ShipError::ClientNotFound(id)).ok()?; - let inventory = item_state.get_character_inventory(&client.character).ok()?; - if ClientItemId(item_id) == MESETA_ITEM_ID { - this.meseta -= amount as usize; - } - else { - let item = inventory.get_by_client_id(&ClientItemId(item_id))?; + trades + .with(&id, |mut this, mut other| { + let trade_request = trade_request.clone(); + async move { + do_trade_action(id, trade_request, client_location, target, &mut this, &mut other, |this, other| { + if this.status == TradeStatus::Trading && other.status == TradeStatus::Trading { + let client = clients.get(&this.client()).ok_or_else(|| ShipError::ClientNotFound(this.client()))?; + let inventory = item_state.get_character_inventory(&client.character)?; + if ClientItemId(item_id) == MESETA_ITEM_ID { + this.meseta -= amount as usize; + } + else { + let item = inventory.get_by_client_id(&ClientItemId(item_id)).ok_or(ItemStateError::InvalidItemId(ClientItemId(item_id)))?; - match &item.item { - InventoryItemDetail::Individual(_) => { - this.items.retain(|item| { - item.item_id() != ClientItemId(item_id) - }) - }, - InventoryItemDetail::Stacked(_stacked_item) => { - let trade_item_index = this.items.iter() - .position(|item| { - item.item_id() == ClientItemId(item_id) - })?; + match &item.item { + InventoryItemDetail::Individual(_) => { + this.items.retain(|item| { + item.item_id() != ClientItemId(item_id) + }) + }, + InventoryItemDetail::Stacked(_stacked_item) => { + let trade_item_index = this.items.iter() + .position(|item| { + item.item_id() == ClientItemId(item_id) + }) + .ok_or(TradeError::InvalidItemId(ClientItemId(item_id)))?; - match this.items[trade_item_index].stacked()?.1.cmp(&(amount as usize)) { - std::cmp::Ordering::Greater => { - *this.items[trade_item_index].stacked_mut()?.1 -= amount as usize; + match this.items[trade_item_index].stacked().ok_or(ItemStateError::InvalidItemId(ClientItemId(item_id)))?.1.cmp(&(amount as usize)) { + std::cmp::Ordering::Greater => { + *this.items[trade_item_index].stacked_mut().ok_or(ItemStateError::InvalidItemId(ClientItemId(item_id)))?.1 -= amount as usize; + }, + std::cmp::Ordering::Equal => { + this.items.remove(trade_item_index); + }, + std::cmp::Ordering::Less => { + return Err(TradeError::SketchyTrade.into()) + } + } }, - std::cmp::Ordering::Equal => { - this.items.remove(trade_item_index); - }, - std::cmp::Ordering::Less => { - return None - } } - }, + } + Ok(()) } - } - let trade_request = trade_request.clone(); - Some(Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter() - .filter(move |client| client.local_client.id() == target as u8) - .map(move |client| { - (client.client, SendShipPacket::DirectMessage(DirectMessage::new(target, GameMessage::TradeRequest(trade_request.clone())))) - }))) + else { + Err(TradeError::MismatchedStatus.into()) + } + + }).await } - else { - None - } - })? - .unwrap_or_else(|| { - trades.remove_trade(&id); - Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter() - .filter(move |client| client.local_client.id() == target as u8) - .map(move |client| { - (client.client, SendShipPacket::CancelTrade(CancelTrade {})) - }) - .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {}))))) - })) + }).await? }, TradeRequestCommand::Confirm => { - Ok(trades - .with(&id, |this, other| -> Option + Send>> { - if status_is(&this.status, &[TradeStatus::Trading]) && status_is(&other.status, &[TradeStatus::Trading, TradeStatus::Confirmed]) { - this.status = TradeStatus::Confirmed; - - let trade_request = trade_request.clone(); - Some(Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter() - .filter(move |client| client.local_client.id() == target as u8) - .map(move |client| { - (client.client, SendShipPacket::DirectMessage(DirectMessage::new(target, GameMessage::TradeRequest(trade_request.clone())))) - }))) + trades + .with(&id, |mut this, mut other| { + let trade_request = trade_request.clone(); + async move { + do_trade_action(id, trade_request, client_location, target, &mut this, &mut other, |this, other| { + if status_is(&this.status, &[TradeStatus::Trading]) && status_is(&other.status, &[TradeStatus::Trading, TradeStatus::Confirmed]) { + this.status = TradeStatus::Confirmed; + Ok(()) + } + else { + Err(TradeError::MismatchedStatus.into()) + } + }).await } - else { - None - } - })? - .unwrap_or_else(|| { - trades.remove_trade(&id); - Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter() - .filter(move |client| client.local_client.id() == target as u8) - .map(move |client| { - (client.client, SendShipPacket::CancelTrade(CancelTrade {})) - }) - .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {}))))) - })) + }).await? }, TradeRequestCommand::FinalConfirm => { - Ok(trades - .with(&id, |this, other| -> Option + Send>> { - if this.status == TradeStatus::Confirmed && (other.status == TradeStatus::Confirmed || other.status == TradeStatus::FinalConfirm) { - this.status = TradeStatus::FinalConfirm; - - let trade_request = trade_request.clone(); - Some(Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter() - .filter(move |client| client.local_client.id() == target as u8) - .map(move |client| { - (client.client, SendShipPacket::DirectMessage(DirectMessage::new(target, GameMessage::TradeRequest(trade_request.clone())))) - }))) + trades + .with(&id, |mut this, mut other| { + let trade_request = trade_request.clone(); + async move { + do_trade_action(id, trade_request, client_location, target, &mut this, &mut other, |this, other| { + if this.status == TradeStatus::Confirmed && (other.status == TradeStatus::Confirmed || other.status == TradeStatus::FinalConfirm) { + this.status = TradeStatus::FinalConfirm; + Ok(()) + } + else { + Err(TradeError::MismatchedStatus.into()) + } + }).await } - else { - None - } - })? - .unwrap_or_else(|| { - trades.remove_trade(&id); - Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter() - .filter(move |client| client.local_client.id() == target as u8) - .map(move |client| { - (client.client, SendShipPacket::CancelTrade(CancelTrade {})) - }) - .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {}))))) - })) + }).await? }, TradeRequestCommand::Cancel => { trades.remove_trade(&id); - Ok(Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter() + Ok(Box::new(client_location.get_all_clients_by_client(id).await?.into_iter() .filter(move |client| client.local_client.id() == target as u8) .map(move |client| { (client.client, SendShipPacket::CancelTrade(CancelTrade {})) @@ -298,10 +282,10 @@ pub async fn inner_items_to_trade(id: ClientId, clients: &mut Clients, item_state: &mut ItemState, trades: &mut TradeState) - -> Result + Send>, anyhow::Error> + -> Result + Send>, ShipError> { - Ok(trades - .with(&id, |this, other| -> Result + Send>, anyhow::Error> { + let pkts: Result + Send>, ShipError> = trades + .with(&id, |mut this, other| async move { if status_is_not(&this.status, &[TradeStatus::FinalConfirm]) || status_is_not(&other.status, &[TradeStatus::FinalConfirm, TradeStatus::ItemsChecked]) { return Err(TradeError::MismatchedStatus.into()) } @@ -379,29 +363,32 @@ pub async fn inner_items_to_trade(id: ClientId, } } }) - .collect::, anyhow::Error>>()?; + .collect::, ShipError>>()?; this.status = TradeStatus::ItemsChecked; if this.status == TradeStatus::ItemsChecked && other.status == TradeStatus::ItemsChecked { Ok(Box::new(vec![ (this.client(), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {})), (other.client(), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {})), - ].into_iter())) + ].into_iter()) as Box + Send>) } else { - Ok(Box::new(None.into_iter())) + Ok(Box::new(Vec::new().into_iter()) as Box + Send>) } - })? - .unwrap_or_else(|err| { - log::warn!("trade error: {:?}", err); - let (_this, other) = trades.remove_trade(&id); - Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter() - .filter(move |client| other.as_ref().map(|other| client.client == other.client() ).unwrap_or_else(|| false)) - .map(move |client| { - (client.client, SendShipPacket::CancelTrade(CancelTrade {})) - }) - .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {}))))) - })) + }).await?; + match pkts { + Ok(pkts) => Ok(pkts), + Err(err) => { + log::warn!("trade error: {:?}", err); + let (_this, other) = trades.remove_trade(&id); + Ok(Box::new(client_location.get_all_clients_by_client(id).await?.into_iter() + .filter(move |client| other.as_ref().map(|other| client.client == other.client() ).unwrap_or_else(|| false)) + .map(move |client| { + (client.client, SendShipPacket::CancelTrade(CancelTrade {})) + }) + .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {})))))) + } + } } pub async fn items_to_trade(id: ClientId, @@ -418,7 +405,7 @@ pub async fn items_to_trade(id: ClientId, Err(err) => { log::warn!("atrade error: {:?}", err); let (_this, other) = trades.remove_trade(&id); - Ok(Box::new(client_location.get_all_clients_by_client(id)?.into_iter() + Ok(Box::new(client_location.get_all_clients_by_client(id).await?.into_iter() .filter(move |client| other.as_ref().map(|other| client.client == other.client()).unwrap_or_else(|| false)) .map(move |client| { (client.client, SendShipPacket::CancelTrade(CancelTrade {})) @@ -428,13 +415,13 @@ pub async fn items_to_trade(id: ClientId, } } -pub async fn trade_confirmed(id: ClientId, - mut entity_gateway: EG, - client_location: &ClientLocation, - clients: &mut Clients, - item_state: &mut ItemState, - trades: &mut TradeState) - -> Result + Send>, anyhow::Error> +pub async fn trade_confirmed_inner(id: ClientId, + mut entity_gateway: EG, + client_location: &ClientLocation, + clients: &mut Clients, + item_state: &mut ItemState, + trades: &mut TradeState) + -> Result + Send>, ShipError> where EG: EntityGateway { @@ -445,123 +432,136 @@ where (AreaClient, &'a crate::ship::ship::ClientState, crate::ship::trade::ClientTradeState)), } - let trade_instructions = trades - .with(&id, |this, other| -> Result<_, anyhow::Error> { - if status_is_not(&this.status, &[TradeStatus::ItemsChecked]) || status_is_not(&other.status, &[TradeStatus::ItemsChecked, TradeStatus::TradeComplete]) { - return Err(TradeError::MismatchedStatus.into()) + let trade = trades + .with(&id, |mut this, other| { + async move { + if status_is_not(&this.status, &[TradeStatus::ItemsChecked]) || status_is_not(&other.status, &[TradeStatus::ItemsChecked, TradeStatus::TradeComplete]) { + return Err(ShipError::TradeError(TradeError::MismatchedStatus)) + } + this.status = TradeStatus::TradeComplete; + + if this.status == TradeStatus::TradeComplete && other.status == TradeStatus::TradeComplete { + let this_client = clients.get(&this.client()).ok_or_else(|| ShipError::ClientNotFound(this.client()))?; + let other_client = clients.get(&other.client()).ok_or_else(|| ShipError::ClientNotFound(other.client()))?; + let this_local_client = client_location.get_local_client(this.client()).await?; + let other_local_client = client_location.get_local_client(other.client()).await?; + let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + + Ok(TradeReady::BothPlayers(room_id, + (this_local_client, this_client, this.clone()), + (other_local_client, other_client, other.clone()))) + } + else { + Ok(TradeReady::OnePlayer) + } } - this.status = TradeStatus::TradeComplete; + }).await??; - if this.status == TradeStatus::TradeComplete && other.status == TradeStatus::TradeComplete { - let this_client = clients.get(&this.client()).ok_or_else(|| ShipError::ClientNotFound(this.client()))?; - let other_client = clients.get(&other.client()).ok_or_else(|| ShipError::ClientNotFound(other.client()))?; - let this_local_client = client_location.get_local_client(this.client())?; - let other_local_client = client_location.get_local_client(other.client())?; - let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + match trade { + TradeReady::OnePlayer => { + Ok(Box::new(None.into_iter()) as Box + Send>) + }, + TradeReady::BothPlayers(_room_id, (this_local_client, this_client, this), (other_local_client, other_client, other)) => { + let remove_item_packets = this.items + .clone() + .into_iter() + .map(move |item| { + (this_local_client, item) + }) + .chain(other.items + .clone() + .into_iter() + .map(move |item| { + (other_local_client, item) + })) + .map(|(client, item)| { + GameMessage::PlayerNoLongerHasItem(builder::message::player_no_longer_has_item(client, item.item_id(), item.amount() as u32)) + }); - Ok(TradeReady::BothPlayers(room_id, - (this_local_client, this_client, this.clone()), - (other_local_client, other_client, other.clone()))) - } - else { - Ok(TradeReady::OnePlayer) - } - }); + let (this_new_items, other_new_items) = trade_items(item_state, + &mut entity_gateway, + (&this_local_client, &this_client.character, &this.items, Meseta(this.meseta as u32)), + (&other_local_client, &other_client.character, &other.items, Meseta(other.meseta as u32))).await?; - // TODO: this match needs to handle errors better - match trade_instructions { - Ok(Ok(trade)) => { - match trade { - TradeReady::OnePlayer => { - Ok(Box::new(None.into_iter()) as Box + Send>) - }, - TradeReady::BothPlayers(_room_id, (this_local_client, this_client, this), (other_local_client, other_client, other)) => { - let remove_item_packets = this.items + let create_item_packets = this_new_items + .into_iter() + .map(move |item| { + (this_local_client, item) + }) + .chain(other_new_items + .into_iter() + .map(move |item| { + (other_local_client, item) + })) + .map(|(client, item)| { + match item.item { + InventoryItemDetail::Individual(individual_item) => { + GameMessage::CreateItem(builder::message::create_individual_item(client, item.item_id, &individual_item).unwrap()) + }, + InventoryItemDetail::Stacked(stacked_item) => { + GameMessage::CreateItem(builder::message::create_stacked_item(client, item.item_id, &stacked_item.tool, stacked_item.count()).unwrap()) + } + } + }); + + let meseta_packets = vec![(this_local_client, other_local_client, this.meseta), (other_local_client, this_local_client, other.meseta)] + .into_iter() + .filter(|(_, _, meseta)| *meseta != 0) + .flat_map(|(this, other, meseta)| { + [ + GameMessage::PlayerNoLongerHasItem(builder::message::player_no_longer_has_item(this, MESETA_ITEM_ID, meseta as u32)), + GameMessage::CreateItem(builder::message::create_meseta(other, meseta)), + ] + }); + + let clients_in_room = client_location.get_all_clients_by_client(id).await?; + let traded_item_packets = remove_item_packets + .chain(create_item_packets) + .chain(meseta_packets) + .flat_map(move |packet| { + clients_in_room .clone() .into_iter() - .map(move |item| { - (this_local_client, item) - }) - .chain(other.items - .clone() - .into_iter() - .map(move |item| { - (other_local_client, item) - })) - .map(|(client, item)| { - GameMessage::PlayerNoLongerHasItem(builder::message::player_no_longer_has_item(client, item.item_id(), item.amount() as u32)) - }); - - let (this_new_items, other_new_items) = trade_items(item_state, - &mut entity_gateway, - (&this_local_client, &this_client.character, &this.items, Meseta(this.meseta as u32)), - (&other_local_client, &other_client.character, &other.items, Meseta(other.meseta as u32))).await?; - - let create_item_packets = this_new_items - .into_iter() - .map(move |item| { - (this_local_client, item) - }) - .chain(other_new_items - .into_iter() - .map(move |item| { - (other_local_client, item) - })) - .map(|(client, item)| { - match item.item { - InventoryItemDetail::Individual(individual_item) => { - GameMessage::CreateItem(builder::message::create_individual_item(client, item.item_id, &individual_item).unwrap()) - }, - InventoryItemDetail::Stacked(stacked_item) => { - GameMessage::CreateItem(builder::message::create_stacked_item(client, item.item_id, &stacked_item.tool, stacked_item.count()).unwrap()) - } - } - }); - - let meseta_packets = vec![(this_local_client, other_local_client, this.meseta), (other_local_client, this_local_client, other.meseta)] - .into_iter() - .filter(|(_, _, meseta)| *meseta != 0) - .flat_map(|(this, other, meseta)| { - [ - GameMessage::PlayerNoLongerHasItem(builder::message::player_no_longer_has_item(this, MESETA_ITEM_ID, meseta as u32)), - GameMessage::CreateItem(builder::message::create_meseta(other, meseta)), - ] - }); - - let clients_in_room = client_location.get_all_clients_by_client(id)?; - let traded_item_packets = remove_item_packets - .chain(create_item_packets) - .chain(meseta_packets) - .flat_map(move |packet| { - clients_in_room - .clone() - .into_iter() - .filter_map(move |client| { - match packet { - GameMessage::PlayerNoLongerHasItem(ref no_longer) => { - if client.local_client == no_longer.client { - None - } - else { - Some((client.client, SendShipPacket::Message(Message::new(packet.clone())))) - } - } - _ => Some((client.client, SendShipPacket::Message(Message::new(packet.clone())))) + .filter_map(move |client| { + match packet { + GameMessage::PlayerNoLongerHasItem(ref no_longer) => { + if client.local_client == no_longer.client { + None } - }) - }); + else { + Some((client.client, SendShipPacket::Message(Message::new(packet.clone())))) + } + } + _ => Some((client.client, SendShipPacket::Message(Message::new(packet.clone())))) + } + }) + }); - let close_trade = vec![ - (this.client(), SendShipPacket::TradeSuccessful(TradeSuccessful::default())), - (other.client(), SendShipPacket::TradeSuccessful(TradeSuccessful::default())) - ].into_iter(); - Ok(Box::new(traded_item_packets.chain(close_trade))) - } - } - }, - _ => { + let close_trade = vec![ + (this.client(), SendShipPacket::TradeSuccessful(TradeSuccessful::default())), + (other.client(), SendShipPacket::TradeSuccessful(TradeSuccessful::default())) + ].into_iter(); + Ok(Box::new(traded_item_packets.chain(close_trade))) + } + } +} + + +pub async fn trade_confirmed(id: ClientId, + entity_gateway: EG, + client_location: &ClientLocation, + clients: &mut Clients, + item_state: &mut ItemState, + trades: &mut TradeState) + -> Result + Send>, ShipError> +where + EG: EntityGateway +{ + match trade_confirmed_inner(id, entity_gateway, client_location, clients, item_state, trades).await { + Ok(result) => Ok(result), + Err(_err) => { let (_this, other) = trades.remove_trade(&id); - Ok(Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter() + Ok(Box::new(client_location.get_all_clients_by_client(id).await?.into_iter() .filter(move |client| other.as_ref().map(|other| client.client == other.client()).unwrap_or_else(|| false)) .map(move |client| { (client.client, SendShipPacket::CancelTrade(CancelTrade {})) diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 47e4529..f744bc0 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -190,7 +190,7 @@ impl RecvServerPacket for RecvShipPacket { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum SendShipPacket { ShipWelcome(ShipWelcome), LoginResponse(LoginResponse), @@ -514,7 +514,7 @@ impl ShipServerState { }, GameMessage::DropCoordinates(drop_coordinates) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::message::drop_coordinates(id, drop_coordinates, &block.client_location, &mut self.clients, &block.rooms)? + handler::message::drop_coordinates(id, drop_coordinates, &block.client_location, &mut self.clients, &block.rooms).await? }, GameMessage::PlayerNoLongerHasItem(no_longer_has_item) => { let block = self.blocks.with_client(id, &self.clients)?; @@ -525,7 +525,7 @@ impl ShipServerState { GameMessage::PlayerLoadedIn(_) | GameMessage::PlayerWalking(_) | GameMessage::PlayerRunning(_) | GameMessage::PlayerWarped(_) | GameMessage::PlayerChangedFloor(_) | GameMessage::InitializeSpeechNpc(_) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::message::update_player_position(id, msg, &mut self.clients, &block.client_location, &block.rooms)? + handler::message::update_player_position(id, msg, &mut self.clients, &block.client_location, &block.rooms).await? }, GameMessage::ChargeAttack(charge_attack) => { let block = self.blocks.with_client(id, &self.clients)?; @@ -558,7 +558,7 @@ impl ShipServerState { _ => { let cmsg = msg.clone(); let block = self.blocks.with_client(id, &self.clients)?; - Box::new(block.client_location.get_client_neighbors(id).unwrap().into_iter() + Box::new(block.client_location.get_client_neighbors(id).await.unwrap().into_iter() .map(move |client| { (client.client, SendShipPacket::Message(cmsg.clone())) })) @@ -571,7 +571,7 @@ impl ShipServerState { let block = self.blocks.with_client(id, &self.clients)?; Ok(match &msg.msg { GameMessage::GuildcardSend(guildcard_send) => { - handler::direct_message::guildcard_send(id, guildcard_send, target, &block.client_location, &self.clients) + handler::direct_message::guildcard_send(id, guildcard_send, target, &block.client_location, &self.clients).await }, GameMessage::RequestItem(request_item) => { handler::direct_message::request_item(id, request_item, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_state).await? @@ -605,7 +605,7 @@ impl ShipServerState { }, _ => { let cmsg = msg.clone(); - Box::new(block.client_location.get_all_clients_by_client(id).unwrap().into_iter() + Box::new(block.client_location.get_all_clients_by_client(id).await.unwrap().into_iter() .filter(move |client| client.local_client.id() == target as u8) .map(move |client| { (client.client, SendShipPacket::DirectMessage(cmsg.clone())) @@ -650,7 +650,7 @@ impl ServerState for ShipServerState { RecvShipPacket::QuestDetailRequest(questdetailrequest) => { let block = self.blocks.with_client(id, &self.clients)?; match questdetailrequest.menu { - QUEST_SELECT_MENU_ID => handler::quest::quest_detail(id, questdetailrequest, &block.client_location, &mut block.rooms)?, + QUEST_SELECT_MENU_ID => handler::quest::quest_detail(id, questdetailrequest, &block.client_location, &mut block.rooms).await?, _ => unreachable!(), } }, @@ -658,27 +658,27 @@ impl ServerState for ShipServerState { let block = self.blocks.with_client(id, &self.clients)?; match menuselect.menu { SHIP_MENU_ID => { - let leave_lobby = handler::lobby::remove_from_lobby(id, &mut block.client_location).into_iter().into_iter().flatten(); + let leave_lobby = handler::lobby::remove_from_lobby(id, &mut block.client_location).await.into_iter().into_iter().flatten(); let select_ship = handler::ship::selected_ship(id, menuselect, &self.ship_list)?; Box::new(leave_lobby.chain(select_ship)) } BLOCK_MENU_ID => { - let leave_lobby = handler::lobby::remove_from_lobby(id, &mut block.client_location).into_iter().into_iter().flatten(); + let leave_lobby = handler::lobby::remove_from_lobby(id, &mut block.client_location).await.into_iter().into_iter().flatten(); let select_block = handler::lobby::block_selected(id, menuselect, &mut self.clients, &self.item_state)?.into_iter(); Box::new(leave_lobby.chain(select_block)) } - ROOM_MENU_ID => handler::room::join_room(id, menuselect, &mut block.client_location, &mut self.clients, &mut self.item_state, &mut block.rooms)?, - QUEST_CATEGORY_MENU_ID => handler::quest::select_quest_category(id, menuselect, &block.client_location, &mut block.rooms)?, + ROOM_MENU_ID => handler::room::join_room(id, menuselect, &mut block.client_location, &mut self.clients, &mut self.item_state, &mut block.rooms).await?, + QUEST_CATEGORY_MENU_ID => handler::quest::select_quest_category(id, menuselect, &block.client_location, &mut block.rooms).await?, _ => unreachable!(), } }, RecvShipPacket::QuestMenuSelect(questmenuselect) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::quest::player_chose_quest(id, questmenuselect, &mut self.clients, &block.client_location, &mut block.rooms)? + handler::quest::player_chose_quest(id, questmenuselect, &mut self.clients, &block.client_location, &mut block.rooms).await? }, RecvShipPacket::MenuDetail(menudetail) => { let block = self.blocks.with_client(id, &self.clients)?; - Box::new(handler::lobby::get_room_tab_info(id, menudetail, &mut block.client_location, &self.clients, &mut block.rooms)?.into_iter()) + Box::new(handler::lobby::get_room_tab_info(id, menudetail, &mut block.client_location, &self.clients, &mut block.rooms).await?.into_iter()) }, RecvShipPacket::RoomPasswordReq(room_password_req) => { let block = self.blocks.with_client(id, &self.clients)?; @@ -689,7 +689,7 @@ impl ServerState for ShipServerState { menu: room_password_req.menu, item: room_password_req.item, }; - handler::room::join_room(id, &menuselect, &mut block.client_location, &mut self.clients, &mut self.item_state, &mut block.rooms)? + handler::room::join_room(id, &menuselect, &mut block.client_location, &mut self.clients, &mut self.item_state, &mut block.rooms).await? } else { Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Incorrect password".into())))].into_iter()) @@ -697,7 +697,7 @@ impl ServerState for ShipServerState { }, RecvShipPacket::CharData(chardata) => { let block = self.blocks.with_client(id, &self.clients)?; - Box::new(handler::lobby::send_player_to_lobby(id, chardata, &mut block.client_location, &self.clients, &self.item_state)?.into_iter()) + Box::new(handler::lobby::send_player_to_lobby(id, chardata, &mut block.client_location, &self.clients, &self.item_state).await?.into_iter()) }, RecvShipPacket::Message(msg) => { self.message(id, msg).await? @@ -707,33 +707,33 @@ impl ServerState for ShipServerState { }, RecvShipPacket::PlayerChat(msg) => { let block = self.blocks.with_client(id, &self.clients)?; - Box::new(handler::communication::player_chat(id, msg, &block.client_location, &self.clients)?) + Box::new(handler::communication::player_chat(id, msg, &block.client_location, &self.clients).await?) }, RecvShipPacket::CreateRoom(create_room) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::room::create_room(id, create_room, &mut block.client_location, &mut self.clients, &mut self.item_state, &mut block.rooms)? + handler::room::create_room(id, create_room, &mut block.client_location, &mut self.clients, &mut self.item_state, &mut block.rooms).await? }, RecvShipPacket::RoomNameRequest(_req) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::room::room_name_request(id, &block.client_location, &block.rooms) + handler::room::room_name_request(id, &block.client_location, &block.rooms).await }, RecvShipPacket::UpdateConfig(pkt) => { handler::settings::update_config(id, pkt, &mut self.clients, self.entity_gateway.clone()).await }, RecvShipPacket::ViewInfoboardRequest(_pkt) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::communication::request_infoboard(id, &block.client_location, &self.clients) + handler::communication::request_infoboard(id, &block.client_location, &self.clients).await }, RecvShipPacket::WriteInfoboard(pkt) => { handler::communication::write_infoboard(id, pkt, &mut self.clients, self.entity_gateway.clone()).await }, RecvShipPacket::RoomListRequest(_req) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::room::request_room_list(id, &block.client_location, &block.rooms) + handler::room::request_room_list(id, &block.client_location, &block.rooms).await }, RecvShipPacket::Like62ButCooler(cool62) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::room::cool_62(id, cool62, &block.client_location) + handler::room::cool_62(id, cool62, &block.client_location).await }, RecvShipPacket::ClientCharacterData(_) => { // TOOD: validate this in some way? @@ -741,11 +741,11 @@ impl ServerState for ShipServerState { }, RecvShipPacket::DoneBursting(_) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::room::done_bursting(id, &block.client_location, &mut block.rooms) + handler::room::done_bursting(id, &block.client_location, &mut block.rooms).await }, RecvShipPacket::DoneBursting2(_) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::room::done_bursting(id, &block.client_location, &mut block.rooms) + handler::room::done_bursting(id, &block.client_location, &mut block.rooms).await }, RecvShipPacket::LobbySelect(pkt) => { let block = self.blocks.with_client(id, &self.clients)?; @@ -753,19 +753,19 @@ impl ServerState for ShipServerState { }, RecvShipPacket::RequestQuestList(rql) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::quest::send_quest_category_list(id, rql, &block.client_location, &mut block.rooms)? + handler::quest::send_quest_category_list(id, rql, &block.client_location, &mut block.rooms).await? }, RecvShipPacket::QuestFileRequest(quest_file_request) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::quest::quest_file_request(id, quest_file_request, &block.client_location, &mut block.rooms)? + handler::quest::quest_file_request(id, quest_file_request, &block.client_location, &mut block.rooms).await? }, RecvShipPacket::QuestChunkAck(quest_chunk_ack) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::quest::quest_chunk_ack(id, quest_chunk_ack, &block.client_location, &mut block.rooms)? + handler::quest::quest_chunk_ack(id, quest_chunk_ack, &block.client_location, &mut block.rooms).await? }, RecvShipPacket::DoneLoadingQuest(_) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::quest::done_loading_quest(id, &mut self.clients, &block.client_location)? + handler::quest::done_loading_quest(id, &mut self.clients, &block.client_location).await? }, RecvShipPacket::FullCharacterData(_full_character_data) => { Box::new(None.into_iter()) @@ -799,19 +799,19 @@ impl ServerState for ShipServerState { async fn on_disconnect(&mut self, id: ClientId) -> Result, anyhow::Error> { let client = self.clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; let block = self.blocks.with_client(id, &self.clients)?; - let area_client = block.client_location.get_local_client(id)?; - let neighbors = block.client_location.get_client_neighbors(id)?; + let area_client = block.client_location.get_local_client(id).await?; + let neighbors = block.client_location.get_client_neighbors(id).await?; - let pkt = match block.client_location.get_area(id)? { + let pkt = match block.client_location.get_area(id).await? { RoomLobby::Room(room) => { if neighbors.is_empty() { block.rooms[room.0] = None; } - let leader = block.client_location.get_room_leader(room)?; + let leader = block.client_location.get_room_leader(room).await?; SendShipPacket::LeaveRoom(LeaveRoom::new(area_client.local_client.id(), leader.local_client.id())) }, RoomLobby::Lobby(lobby) => { - let leader = block.client_location.get_lobby_leader(lobby)?; + let leader = block.client_location.get_lobby_leader(lobby).await?; SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())) } }; @@ -820,7 +820,7 @@ impl ServerState for ShipServerState { shipgate_sender(ShipMessage::RemoveUser(client.user.id)); } - block.client_location.remove_client_from_area(id); + block.client_location.remove_client_from_area(id).await; self.item_state.remove_character_from_room(&client.character); if let Some(mut client) = self.clients.remove(&id) { diff --git a/src/ship/trade.rs b/src/ship/trade.rs index 311cf9e..790c354 100644 --- a/src/ship/trade.rs +++ b/src/ship/trade.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use std::cell::RefCell; - use crate::common::serverstate::ClientId; use crate::ship::items; +use async_std::sync::{Mutex, MutexGuard}; +use futures::future::Future; #[derive(Debug, Clone)] pub enum TradeItem { @@ -67,7 +67,7 @@ impl ClientTradeState { pub fn client(&self) -> ClientId { self.client } - + pub fn other_client(&self) -> ClientId { self.other_client } @@ -83,7 +83,7 @@ pub enum TradeStateError { #[derive(Default, Debug)] pub struct TradeState { - trades: HashMap>, + trades: HashMap>, } impl TradeState { @@ -95,7 +95,7 @@ impl TradeState { meseta: 0, status: TradeStatus::SentRequest, }; - self.trades.insert(*sender, RefCell::new(state)); + self.trades.insert(*sender, Mutex::new(state)); let state = ClientTradeState { client: *receiver, @@ -104,26 +104,26 @@ impl TradeState { meseta: 0, status: TradeStatus::ReceivedRequest, }; - self.trades.insert(*receiver, RefCell::new(state)); + self.trades.insert(*receiver, Mutex::new(state)); } pub fn in_trade(&self, client: &ClientId) -> bool { self.trades.contains_key(client) } - pub fn with (&self, client: &ClientId, func: F) -> Result + pub async fn with<'a, T, F, Fut> (&'a self, client: &ClientId, func: F) -> Result where - F: Fn(&mut ClientTradeState, &mut ClientTradeState) -> T + F: FnOnce(MutexGuard<'a, ClientTradeState>, MutexGuard<'a, ClientTradeState>) -> Fut + 'a, + Fut: Future { - let mut c1 = self.trades.get(client).ok_or(TradeStateError::ClientNotInTrade(*client))?.borrow_mut(); - let mut c2 = self.trades.get(&c1.other_client).ok_or(TradeStateError::ClientNotInTrade(c1.other_client))?.borrow_mut(); + let c1 = self.trades.get(client).ok_or(TradeStateError::ClientNotInTrade(*client))?.lock().await; + let c2 = self.trades.get(&c1.other_client).ok_or(TradeStateError::ClientNotInTrade(c1.other_client))?.lock().await; // sanity check if c1.client != c2.other_client { return Err(TradeStateError::MismatchedTrade(c1.client, c2.client)); } - - Ok(func(&mut c1, &mut c2)) + Ok(func(c1, c2).await) } // TODO: is it possible for this to not return Options? diff --git a/tests/test_trade.rs b/tests/test_trade.rs index 0d97cd7..fd6efe0 100644 --- a/tests/test_trade.rs +++ b/tests/test_trade.rs @@ -2251,8 +2251,14 @@ async fn test_trade_not_enough_inventory_space_individual() { assert_eq!(ack.len(), 0); let ack = ship.handle(ClientId(2), &RecvShipPacket::TradeConfirmed(TradeConfirmed { - })).await.err().unwrap(); - assert!(matches!(ack.downcast::().unwrap(), ItemStateError::InventoryError(InventoryError::InventoryFull))); + })).await.unwrap().collect::>(); + + 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); @@ -2363,8 +2369,13 @@ async fn test_trade_not_enough_inventory_space_stacked() { assert_eq!(ack.len(), 0); let ack = ship.handle(ClientId(2), &RecvShipPacket::TradeConfirmed(TradeConfirmed { - })).await.err().unwrap(); - assert!(matches!(ack.downcast::().unwrap(), ItemStateError::InventoryError(InventoryError::InventoryFull))); + })).await.unwrap().collect::>(); + + 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); @@ -2472,8 +2483,13 @@ async fn test_trade_stack_too_big() { assert_eq!(ack.len(), 0); let ack = ship.handle(ClientId(2), &RecvShipPacket::TradeConfirmed(TradeConfirmed { - })).await.err().unwrap(); - assert!(matches!(ack.downcast::().unwrap(), ItemStateError::InventoryError(InventoryError::StackFull))); + })).await.unwrap().collect::>(); + + 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); @@ -3094,8 +3110,13 @@ async fn test_invalid_trade_when_both_inventories_are_full() { assert_eq!(ack.len(), 0); let ack = ship.handle(ClientId(2), &RecvShipPacket::TradeConfirmed(TradeConfirmed { - })).await.err().unwrap(); - assert!(matches!(ack.downcast::().unwrap(), ItemStateError::InventoryError(InventoryError::InventoryFull))); + })).await.unwrap().collect::>(); + + 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); From 27931adb5af36fa7c2459442df8af71a94d3c062 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 18 Sep 2022 21:05:48 -0600 Subject: [PATCH 2/9] clippy found some new problems --- src/entity/gateway/postgres/postgres.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/entity/gateway/postgres/postgres.rs b/src/entity/gateway/postgres/postgres.rs index 5a71cf5..813c810 100644 --- a/src/entity/gateway/postgres/postgres.rs +++ b/src/entity/gateway/postgres/postgres.rs @@ -162,10 +162,10 @@ async fn save_user(conn: &mut sqlx::PgConnection, user: &UserAccountEntity) -> R sqlx::query("UPDATE user_accounts set username=$1, password=$2, banned=$3, muted=$4, flags=$5 where id=$6") .bind(&user.username) .bind(&user.password) - .bind(&user.banned_until) - .bind(&user.muted_until) - .bind(&user.flags) - .bind(&user.id.0) + .bind(user.banned_until) + .bind(user.muted_until) + .bind(user.flags) + .bind(user.id.0) .execute(conn).await?; Ok(()) } @@ -200,11 +200,11 @@ async fn save_user_settings(conn: &mut sqlx::PgConnection, settings: &UserSettin .bind(settings.settings.blocked_users.iter().copied().flat_map(|i| i.to_le_bytes().to_vec()).collect::>()) .bind(&settings.settings.keyboard_config.to_vec()) .bind(&settings.settings.gamepad_config.to_vec()) - .bind(&settings.settings.option_flags) + .bind(settings.settings.option_flags) .bind(&settings.settings.shortcuts.to_vec()) .bind(&settings.settings.symbol_chats.to_vec()) .bind(settings.settings.team_name.iter().copied().flat_map(|i| i.to_le_bytes().to_vec()).collect::>()) - .bind(&settings.id.0) + .bind(settings.id.0) .fetch_one(conn).await?; Ok(()) } From fdce44cdd8c92ed0d49a4aab758fe16984bbb8db Mon Sep 17 00:00:00 2001 From: jake Date: Tue, 18 Oct 2022 04:46:21 -0600 Subject: [PATCH 3/9] refactor the rest of the fucking code --- Cargo.lock | 10 +- Cargo.toml | 4 +- src/bin/login.rs | 8 +- src/bin/main.rs | 98 ++- src/bin/patch.rs | 4 +- src/bin/ship.rs | 10 +- src/common/interserver.rs | 8 +- src/common/mainloop/client.rs | 36 +- src/common/mainloop/interserver.rs | 10 +- src/common/mainloop/mod.rs | 511 ++++++++++++++- src/common/serverstate.rs | 15 +- src/lib.rs | 3 +- src/login/character.rs | 91 +-- src/login/login.rs | 36 +- src/patch/patch.rs | 38 +- src/ship/items/actions.rs | 58 +- src/ship/items/apply_item.rs | 2 +- src/ship/items/state.rs | 368 ++++++++--- src/ship/items/tasks.rs | 38 +- src/ship/location.rs | 9 +- src/ship/map/area.rs | 6 +- src/ship/map/maps.rs | 1 - src/ship/mod.rs | 1 + src/ship/packet/builder/lobby.rs | 59 +- src/ship/packet/builder/mod.rs | 5 +- src/ship/packet/builder/room.rs | 18 +- src/ship/packet/handler/auth.rs | 29 +- src/ship/packet/handler/communication.rs | 76 ++- src/ship/packet/handler/direct_message.rs | 590 ++++++++++-------- src/ship/packet/handler/lobby.rs | 149 +++-- src/ship/packet/handler/message.rs | 566 +++++++++-------- src/ship/packet/handler/quest.rs | 367 +++++++---- src/ship/packet/handler/room.rs | 330 ++++++---- src/ship/packet/handler/settings.rs | 97 +-- src/ship/packet/handler/ship.rs | 16 +- src/ship/packet/handler/trade.rs | 240 +++---- src/ship/quests.rs | 25 +- src/ship/room.rs | 133 +++- src/ship/ship.rs | 450 ++++++++------ src/ship/trade.rs | 45 +- tests/common.rs | 24 +- tests/test_bank.rs | 172 ++--- tests/test_character.rs | 8 +- tests/test_character_data.rs | 18 + tests/test_exp_gain.rs | 101 +-- tests/test_item_actions.rs | 16 +- tests/test_item_pickup.rs | 106 ++-- tests/test_item_use.rs | 32 +- tests/test_mags.rs | 16 +- tests/test_rooms.rs | 33 +- tests/test_shops.rs | 165 ++--- tests/test_trade.rs | 724 +++++++++++----------- 52 files changed, 3757 insertions(+), 2218 deletions(-) create mode 100644 tests/test_character_data.rs diff --git a/Cargo.lock b/Cargo.lock index e85e554..8b5c4c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1061,7 +1061,6 @@ checksum = "739e9d7726dc32173fed2d69d17eef3c54682169e4e20ff1d0a45dcd37063cef" [[package]] name = "libpso" version = "0.1.0" -source = "git+http://git.sharnoth.com/jake/libpso#4fba0529aef169c67a99709582109ca5c68f15de" dependencies = [ "chrono", "psopacket", @@ -1420,7 +1419,6 @@ dependencies = [ [[package]] name = "psopacket" version = "1.0.0" -source = "git+http://git.sharnoth.com/jake/libpso#4fba0529aef169c67a99709582109ca5c68f15de" dependencies = [ "proc-macro2", "quote", @@ -2071,18 +2069,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 0dc9c0c..9a69268 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "elseware" version = "0.1.0" authors = ["Jake Probst "] -edition = "2018" +edition = "2021" [dependencies] libpso = { git = "http://git.sharnoth.com/jake/libpso" } @@ -22,7 +22,7 @@ fern = { version = "0.5", features = ["colored"] } byteorder = "1" enum-utils = "0.1.2" derive_more = { version = "0.99.3", features = ["display"]} -thiserror = "1.0.15" +thiserror = "1.0.37" ages-prs = "0.1" async-trait = "0.1.51" async-recursion= "1.0.0" diff --git a/src/bin/login.rs b/src/bin/login.rs index 958693c..6490973 100644 --- a/src/bin/login.rs +++ b/src/bin/login.rs @@ -1,11 +1,12 @@ use log::{info}; -use elseware::entity::gateway::postgres::PostgresGateway; +//use elseware::entity::gateway::postgres::PostgresGateway; use elseware::login::login::LoginServerState; use elseware::login::character::CharacterServerState; -use elseware::common::mainloop::{login_mainloop, character_mainloop}; -use elseware::common::interserver::AuthToken; +//use elseware::common::mainloop::{login_mainloop, character_mainloop}; +//use elseware::common::interserver::AuthToken; fn main() { + /* let colors = fern::colors::ColoredLevelConfig::new() .error(fern::colors::Color::Red) .warn(fern::colors::Color::Yellow) @@ -48,4 +49,5 @@ fn main() { async_std::task::block_on(async move { futures::future::join_all(vec![login_loop, character_loop]).await }); + */ } diff --git a/src/bin/main.rs b/src/bin/main.rs index 76c63a6..9054c28 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,13 +1,15 @@ use std::net::Ipv4Addr; use log::{info}; +use async_std::channel; use elseware::patch::patch::{PatchServerState, generate_patch_tree, load_config, load_motd}; use elseware::login::login::LoginServerState; use elseware::login::character::CharacterServerState; -use elseware::ship::ship::ShipServerStateBuilder; +//use elseware::ship::ship::ShipServerStateBuilder; use elseware::entity::account::{NewUserAccountEntity, NewUserSettingsEntity}; #[allow(unused_imports)] -use elseware::entity::gateway::{EntityGateway, InMemoryGateway, PostgresGateway}; +//use elseware::entity::gateway::{EntityGateway, InMemoryGateway, PostgresGateway}; +use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; use elseware::entity::character::NewCharacterEntity; use elseware::entity::item::{NewItemEntity, ItemDetail, InventoryItemEntity}; use elseware::common::interserver::AuthToken; @@ -330,6 +332,7 @@ fn main() { entity_gateway.set_character_bank(&character.id, &item::BankEntity::default(), &item::BankName("".into())).await.unwrap(); } + /* info!("[patch] starting server"); let patch_config = load_config(); let patch_motd = load_motd(); @@ -376,5 +379,96 @@ fn main() { let ship_loop3 = ship_mainloop(*ship_state, elseware::ship::ship::SHIP_PORT+3000, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT); futures::future::join_all(vec![patch_loop, login_loop, character_loop, ship_loop, ship_loop2, ship_loop3]).await; + */ + + info!("[patch] starting server"); + let patch_config = load_config(); + let patch_motd = load_motd(); + let (patch_file_tree, patch_file_lookup) = generate_patch_tree(patch_config.path.as_str()); + let patch_state = PatchServerState::new(patch_file_tree, patch_file_lookup, patch_motd); + let patch_loop = async_std::task::spawn(async move { + elseware::common::mainloop::run_server(patch_state, patch_config.port).await; + }); + + info!("[auth] starting server"); + let auth_entity_gateway = entity_gateway.clone(); + let login_state = LoginServerState::new(auth_entity_gateway, "127.0.0.1".parse().unwrap()); + let login_loop = async_std::task::spawn(async move { + elseware::common::mainloop::run_server(login_state, elseware::login::login::LOGIN_PORT).await; + }); + + info!("[character] starting server"); + let character_entity_gateway = entity_gateway.clone(); + let char_state = CharacterServerState::new(character_entity_gateway, AuthToken("".into())); + let sub_char_state = char_state.clone(); + let character_loop = async_std::task::spawn(async move { + elseware::common::mainloop::run_server(sub_char_state, elseware::login::character::CHARACTER_PORT).await; + }); + + let sub_char_state = char_state.clone(); + let inter_character_loop = async_std::task::spawn(async move { + elseware::common::mainloop::run_interserver_listen(sub_char_state, elseware::login::login::COMMUNICATION_PORT).await; + }); + /* + let inter_character_loop_recv = async_std::task::spawn(|| async { + crate::common::mainloop::run_interserver_receiver(char_state, elseware::login::character::COMMUNICATION_PORT).await + }); + let inter_character_loop_send = async_std::task::spawn(|| async { + crate::common::mainloop::run_interserver_sender(char_state, interserver_rx).await + */ + + let ship_entity_gateway = entity_gateway.clone(); + info!("[ship] starting server"); + + //let (interserver_tx, interserver_rx) = async_std::channel::unbounded(); +/* + let ship_state = ShipServerStateBuilder::default() + .name("US/Sona-Nyl".into()) + .ip(Ipv4Addr::new(127,0,0,1)) + .port(elseware::ship::ship::SHIP_PORT) + .gateway(thread_entity_gateway) + .interserver_sender(|msg| async move { + interserver_tx.send(msg).await + }) + .build(); + let sub_ship_state = ship_state.clone(); + let ship_loop = async_std::task::spawn(|| async { + crate::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT); + }); + /* + /*, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT*/ + let inter_ship_loop = async_std::task::spawn(|| async { + crate::common::mainloop::run_interserver_receiver(ship_state, elseware::login::login::COMMUNICATION_PORT); + }); + */ + + let ship_entity_gateway = entity_gateway.clone(); + let ship_state = Box::new(ShipServerStateBuilder::default() + .name("EU/Dylath-Leen".into()) + .ip(Ipv4Addr::new(127,0,0,1)) + .port(elseware::ship::ship::SHIP_PORT+2000) + .gateway(thread_entity_gateway) + .build()); + let sub_ship_state = ship_state.clone(); + let ship_loop2 = async_std::task::spawn(|| async { + crate::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT); + }); + + let thread_entity_gateway = entity_gateway.clone(); + let ship_state = Box::new(ShipServerStateBuilder::default() + .name("JP/Thalarion".into()) + .ip(Ipv4Addr::new(127,0,0,1)) + .port(elseware::ship::ship::SHIP_PORT+3000) + .gateway(thread_entity_gateway) + .build()); + let sub_ship_state = ship_state.clone(); + let ship_loop3 = async_std::task::spawn(|| async { + crate::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT); + }); + futures::future::join_all(vec![patch_loop, login_loop, character_loop, ship_loop, ship_loop2, ship_loop3]).await; + */ + + futures::future::join_all(vec![patch_loop, login_loop, character_loop, inter_character_loop]).await; + }); } diff --git a/src/bin/patch.rs b/src/bin/patch.rs index a12df4e..f6cf2bc 100644 --- a/src/bin/patch.rs +++ b/src/bin/patch.rs @@ -1,8 +1,9 @@ use elseware::patch::patch::{PatchServerState, generate_patch_tree, load_config_env, load_motd}; use log::{info}; -use elseware::common::mainloop::patch_mainloop; +//use elseware::common::mainloop::patch_mainloop; fn main() { + /* info!("[patch] starting server"); let patch_config = load_config_env(); let patch_motd = load_motd(); @@ -13,4 +14,5 @@ fn main() { async_std::task::block_on(async move { patch_loop.await }); + */ } diff --git a/src/bin/ship.rs b/src/bin/ship.rs index 3c6d14e..29bbab3 100644 --- a/src/bin/ship.rs +++ b/src/bin/ship.rs @@ -1,10 +1,11 @@ use log::{info}; -use elseware::entity::gateway::postgres::PostgresGateway; -use elseware::ship::ship::ShipServerStateBuilder; -use elseware::common::mainloop::ship_mainloop; -use elseware::common::interserver::AuthToken; +//use elseware::entity::gateway::postgres::PostgresGateway; +//use elseware::ship::ship::ShipServerStateBuilder; +//use elseware::common::mainloop::ship_mainloop; +//use elseware::common::interserver::AuthToken; fn main() { + /* let colors = fern::colors::ColoredLevelConfig::new() .error(fern::colors::Color::Red) .warn(fern::colors::Color::Yellow) @@ -52,4 +53,5 @@ fn main() { async_std::task::block_on(async move { ship_loop.await }); + */ } diff --git a/src/common/interserver.rs b/src/common/interserver.rs index db2f6a1..ac37d65 100644 --- a/src/common/interserver.rs +++ b/src/common/interserver.rs @@ -1,4 +1,6 @@ use std::net::Ipv4Addr; +use async_std::sync::Arc; +use async_std::channel; use serde::{Serialize, Deserialize}; use serde::de::DeserializeOwned; use crate::entity::account::UserAccountId; @@ -46,12 +48,14 @@ pub enum ShipMessage { #[async_trait::async_trait] -pub trait InterserverActor { +pub trait InterserverActor: Clone { type SendMessage: Serialize; type RecvMessage: DeserializeOwned; type Error; async fn on_connect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)>; - async fn action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result, Self::Error>; + async fn on_action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result, Self::Error>; async fn on_disconnect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)>; + //fn set_sender(&mut self, server_id: ServerId, func: Arc Box>>>); + fn set_sender(&mut self, server_id: ServerId, tx: channel::Sender); } diff --git a/src/common/mainloop/client.rs b/src/common/mainloop/client.rs index 52cc503..456fb82 100644 --- a/src/common/mainloop/client.rs +++ b/src/common/mainloop/client.rs @@ -1,9 +1,10 @@ -use std::pin::Pin; +use std::pin::pin; use futures::future::Future; use log::{trace, info, warn}; use async_std::sync::{Arc, Mutex}; use async_std::io::prelude::{ReadExt, WriteExt}; use std::collections::HashMap; +use std::pin::Pin; use libpso::crypto::{PSOCipher, NullCipher, CipherError}; use libpso::PacketParseError; @@ -39,15 +40,16 @@ impl From for NetworkError { } } -struct PacketReceiver { - socket: Arc, - cipher: Arc>>, +pub struct PacketReceiver { + socket: async_std::net::TcpStream, + //cipher: Arc>>, + cipher: C, recv_buffer: Vec, incoming_data: Vec, } -impl PacketReceiver { - fn new(socket: Arc, cipher: Arc>>) -> PacketReceiver { +impl PacketReceiver { + pub fn new(socket: async_std::net::TcpStream, cipher: C) -> PacketReceiver { PacketReceiver { socket, cipher, @@ -59,7 +61,7 @@ impl PacketReceiver { async fn fill_recv_buffer(&mut self) -> Result<(), NetworkError> { let mut data = [0u8; 0x8000]; - let mut socket = &*self.socket; + let mut socket = self.socket.clone(); let len = socket.read(&mut data).await?; if len == 0 { return Err(NetworkError::ClientDisconnected); @@ -68,17 +70,17 @@ impl PacketReceiver { self.recv_buffer.extend_from_slice(&data[..len]); let mut dec_buf = { - let mut cipher = self.cipher.lock().await; - let block_chunk_len = self.recv_buffer.len() / cipher.block_size() * cipher.block_size(); + //let mut cipher = self.cipher.lock().await; + let block_chunk_len = self.recv_buffer.len() / self.cipher.block_size() * self.cipher.block_size(); let buf = self.recv_buffer.drain(..block_chunk_len).collect(); - cipher.decrypt(&buf)? + self.cipher.decrypt(&buf)? }; self.incoming_data.append(&mut dec_buf); Ok(()) } - async fn recv_pkts(&mut self) -> Result, NetworkError> { + pub async fn recv_pkts(&mut self) -> Result, NetworkError> { self.fill_recv_buffer().await?; let mut result = Vec::new(); @@ -88,7 +90,7 @@ impl PacketReceiver { } let pkt_size = u16::from_le_bytes([self.incoming_data[0], self.incoming_data[1]]) as usize; let mut pkt_len = pkt_size; - while pkt_len % self.cipher.lock().await.block_size() != 0 { + while pkt_len % self.cipher.block_size() != 0 { pkt_len += 1; } @@ -113,6 +115,7 @@ impl PacketReceiver { Ok(result) } } +/* async fn send_pkt(socket: Arc, cipher: Arc>>, pkt: S) @@ -150,13 +153,14 @@ where { async_std::task::spawn(async move { server_sender.send(ClientAction::NewClient(client_id, client_sender)).await.unwrap(); - let mut pkt_receiver = PacketReceiver::new(socket, cipher); + /* + let mut pkt_receiver = PacketReceiver::new(*socket, cipher); loop { match pkt_receiver.recv_pkts().await { Ok(pkts) => { for pkt in pkts { - info!("[recv from {:?}] {:?}", client_id, pkt); + info!("[recv from {:?}] {:#?}", client_id, pkt); server_sender.send(ClientAction::Packet(client_id, pkt)).await.unwrap(); } }, @@ -174,6 +178,7 @@ where } } } + */ }); } @@ -194,7 +199,7 @@ where *cipher_out.lock().await = outc; } ServerStateAction::Packet(pkt) => { - info!("[send to {:?}] {:?}", client_id, pkt); + info!("[send to {:?}] {:#?}", client_id, pkt); if let Err(err) = send_pkt(socket.clone(), cipher_out.clone(), pkt).await { warn!("[client {:?} send error ] {:?}", client_id, err); } @@ -315,3 +320,4 @@ where })) } +*/ diff --git a/src/common/mainloop/interserver.rs b/src/common/mainloop/interserver.rs index ce1cb66..aab00bb 100644 --- a/src/common/mainloop/interserver.rs +++ b/src/common/mainloop/interserver.rs @@ -10,10 +10,14 @@ use serde::de::DeserializeOwned; use crate::common::interserver::{ServerId, InterserverActor}; +use libpso::crypto::{PSOCipher, NullCipher, CipherError}; +use crate::common::serverstate::{ServerState, SendServerPacket, RecvServerPacket}; use crate::login::character::CharacterServerState; -use crate::ship::ship::ShipServerState; +//use crate::ship::ship::ShipServerState; use crate::entity::gateway::entitygateway::EntityGateway; +use async_std::channel; + #[derive(Debug)] enum MessageReceiverError { //InvalidSize, @@ -46,6 +50,7 @@ impl MessageReceiver { Ok(msg) } } +/* #[derive(Debug)] enum InterserverInputAction { @@ -209,7 +214,9 @@ pub fn login_listen_mainloop(state: Arc(state: Arc>>, ip: std::net::Ipv4Addr, port: u16) -> Pin>> { Box::pin(async_std::task::spawn(async move { let mut id = 0; @@ -258,3 +265,4 @@ pub fn ship_connect_mainloop(state: Arc Pin>> { let patch_state = Arc::new(Mutex::new(patch_state)); let client_mainloop = client_accept_mainloop(patch_state, patch_port); @@ -43,3 +61,488 @@ pub fn ship_mainloop(ship_state: ShipServer let login_communication_mainloop = ship_connect_mainloop(ship_state, comm_ip, comm_port); Box::pin(join_all(vec![client_mainloop, login_communication_mainloop]).map(|_| ())) } +*/ + + +#[derive(Debug)] +enum MessageReceiverError { + //InvalidSize, + InvalidPayload, + //NetworkError(std::io::Error), + Disconnected, +} + +struct MessageReceiver { + socket: async_std::net::TcpStream, +} + +impl MessageReceiver { + fn new(socket: async_std::net::TcpStream) -> MessageReceiver { + MessageReceiver { + socket, + } + } + + async fn recv(&mut self) -> Result { + let mut size_buf = [0u8; 4]; + self.socket.read_exact(&mut size_buf).await.map_err(|_| MessageReceiverError::Disconnected)?; + let size = u32::from_le_bytes(size_buf) as usize; + + let mut payload = vec![0u8; size]; + self.socket.read_exact(&mut payload).await.map_err(|_| MessageReceiverError::Disconnected)?; + let payload = String::from_utf8(payload).map_err(|_| MessageReceiverError::InvalidPayload)?; + + let msg = serde_json::from_str(&payload).map_err(|_| MessageReceiverError::InvalidPayload)?; + Ok(msg) + } +} + + +/* +enum ServerAction { + NewClient(ClientId, channel::Sender), + Packet(ClientId, S), + Disconnect(ClientId), +} +*/ + +async fn recv_loop(mut state: STATE, + socket: async_std::net::TcpStream, + client_id: ClientId, + cipher: C, + clients: Arc>>>) +where + STATE: ServerState + Send, + S: SendServerPacket + Debug + Send, + R: RecvServerPacket + Debug + Send, + C: PSOCipher + Send, + E: std::fmt::Debug + Send, +{ + let mut pkt_receiver = PacketReceiver::new(socket, cipher); + loop { + match pkt_receiver.recv_pkts::().await { + Ok(pkts) => { + for pkt in pkts { + info!("[recv from {:?}] {:#?}", client_id, pkt); + match state.handle(client_id, pkt).await { + Ok(response) => { + for resp in response { + clients + .read() + .await + .get(&resp.0) + .unwrap() + .send(resp.1) + .await; + } + }, + Err(err) => { + warn!("[client recv {:?}] error {:?} ", client_id, err); + } + } + } + }, + Err(err) => { + match err { + NetworkError::ClientDisconnected => { + info!("[client recv {:?}] disconnected", client_id); + for pkt in state.on_disconnect(client_id).await.unwrap() { + clients + .read() + .await + .get(&pkt.0) + .unwrap() + .send(pkt.1) + .await; + } + clients + .write() + .await + .remove(&client_id); + break; + } + _ => { + warn!("[client {:?} recv error] {:?}", client_id, err); + } + } + } + } + } +} + + +async fn send_pkt(socket: &mut async_std::net::TcpStream, + cipher: &mut C, + pkt: &S) + -> Result<(), NetworkError> +where + S: SendServerPacket + std::fmt::Debug, + C: PSOCipher, +{ + let buf = pkt.as_bytes(); + trace!("[send buf] {:?}", buf); + let cbuf = cipher.encrypt(&buf)?; + socket.write_all(&cbuf).await?; + Ok(()) +} + +async fn send_loop(mut socket: async_std::net::TcpStream, client_id: ClientId, mut cipher: C, packet_queue: channel::Receiver) +where + S: SendServerPacket + std::fmt::Debug, + C: PSOCipher, +{ + loop { + let pkt = packet_queue.recv().await.unwrap(); + if let Err(err) = send_pkt(&mut socket, &mut cipher, &pkt).await { + warn!("error sending pkt {:#?} to {:?} {:?}", pkt, client_id, err); + } + } +} + +/* +pub async fn server_multiplex(state: STATE, packet_queue: channel::Receiver>) +where + STATE: ServerState, + S: SendServerPacket + std::fmt::Debug, + R: RecvServerPacket + std::fmt::Debug, + E: std::fmt::Debug, +{ + let mut clients = HashMap::new(); + loop { + let action = packet_queue.recv().await.unwrap(); + + match action { + ServerAction::NewClient(client_id, sender) => { + clients.insert(client_id, sender); + }, + ServerAction::Packet(client_id, pkt) => { + if let Some(sender) = clients.get(&client_id) { + sender.send(pkt).await; + } + }, + ServerAction::Disconnect(client_id) => { + clients.remove(&client_id); + } + } + + } +} +*/ + +pub async fn run_server(mut state: STATE, port: u16) +where + STATE: ServerState + Send + 'static, + S: SendServerPacket + std::fmt::Debug + Send + 'static, + R: RecvServerPacket + std::fmt::Debug + Send, + C: PSOCipher + Send + 'static, + E: std::fmt::Debug + Send, +{ + let listener = async_std::net::TcpListener::bind(&std::net::SocketAddr::from((std::net::Ipv4Addr::new(0,0,0,0), port))).await.unwrap(); + let mut id = 0; + //let (packet_sender, packet_receiver) = async_std::channel::unbounded(); + + let clients = Arc::new(RwLock::new(HashMap::new())); + + //let cstate = state.clone(); + /* + async_std::task::spawn(async move { + server_multiplex(cstate, packet_receiver).await + }); + */ + + loop { + let (mut socket, addr) = listener.accept().await.unwrap(); + id += 1; + + let client_id = crate::common::serverstate::ClientId(id); + info!("new client {:?} {:?} {:?}", client_id, socket, addr); + + let (client_tx, client_rx) = async_std::channel::unbounded(); + //packet_sender.send(ServerAction::NewClient()).await; + + clients + .write() + .await + .insert(client_id, client_tx.clone()); + + let mut cipher_in: Option = None; + let mut cipher_out: Option = None; + + for action in state.on_connect(client_id).await.unwrap() { + match action { + OnConnect::Cipher(cin, cout) => { + cipher_in = Some(cin); + cipher_out = Some(cout); + }, + OnConnect::Packet(pkt) => { + send_pkt(&mut socket, &mut NullCipher {}, &pkt).await; + } + } + } + + let rstate = state.clone(); + let rsocket = socket.clone(); + let rclients = clients.clone(); + async_std::task::spawn(async move { + /* + rstate; + rsocket; + client_id; + cipher_in.unwrap(); + rclients; + */ + //client_tx.send(12).await + recv_loop(rstate, rsocket, client_id, cipher_in.unwrap(), rclients).await + //recv_loop2(rstate, rsocket, client_id, cipher_in.unwrap()).await + }); + + //let sstate = state.clone(); + async_std::task::spawn(async move { + send_loop(socket, client_id, cipher_out.unwrap(), client_rx).await + }); + } +} + +/* +pub async fn listen_interserver(state: STATE, port: u16) +where + STATE: InterserverActor, + S: serde::Serialize, + R: serde::de::DeserializeOwned, +{ + let listener = async_std::net::TcpListener::bind(&std::net::SocketAddr::from((std::net::Ipv4Addr::new(0,0,0,0), port))).await.unwrap(); + let mut id = 0; + + loop { + let (socket, addr) = listener.accept().await.unwrap(); + info!("new interserver connection: {:?} {:?}", socket, addr); + + id += 1; + let server_id = crate::common::interserver::ServerId(id); + } +} + + +pub async fn run_interserver_receiver(state: STATE, ip: std::net::Ipv4Addr, port: u16) +where + STATE: InterserverActor, + S: serde::Serialize, + R: serde::de::DeserializeOwned, +{ + loop { + + } + + +} + +pub async fn run_interserver_sender(state: STATE, to_send: channel::Receiver) +where + STATE: InterserverActor, + S: serde::Serialize, + R: serde::de::DeserializeOwned, +{ + loop { + let msg = to_send.recv().await.unwrap(); + + let response = state.on_action(msg); + + + + + } + +} +*/ + +async fn interserver_recv_loop(mut state: STATE, server_id: ServerId, socket: async_std::net::TcpStream, ships: Arc>>>) +where + STATE: InterserverActor + Send, + S: serde::Serialize + Debug + Send, + R: serde::de::DeserializeOwned + Debug + Send, + E: Debug + Send, +{ + let mut msg_receiver = MessageReceiver::new(socket); + + loop { + match msg_receiver.recv::().await { + Ok(msg) => { + info!("[interserver recv {:?}] {:?}", server_id, msg); + match state.on_action(server_id, msg).await { + Ok(response) => { + for resp in response { + ships + .read() + .await + .get(&resp.0) + .unwrap() + .send(resp.1) + .await; + } + }, + Err(err) => { + warn!("[interserver recv {:?}] error {:?}", server_id, err); + } + } + }, + Err(err) => { + if let MessageReceiverError::Disconnected = err { + info!("[interserver recv {:?}] disconnected", server_id); + for (_, sender) in ships.read().await.iter() { + for pkt in state.on_disconnect(server_id).await { + ships + .read() + .await + .get(&pkt.0) + .unwrap() + .send(pkt.1) + .await; + } + } + ships + .write() + .await + .remove(&server_id); + break; + } + info!("[interserver recv {:?}] error {:?}", server_id, err); + } + } + } +} + +async fn interserver_send_loop(server_id: ServerId, mut socket: async_std::net::TcpStream, to_send: channel::Receiver) +where + S: serde::Serialize + std::fmt::Debug, +{ + loop { + let msg = to_send.recv().await.unwrap(); + let payload = serde_json::to_string(&msg); + + if let Ok(payload) = payload { + let len_bytes = u32::to_le_bytes(payload.len() as u32); + if let Err(err) = socket.write_all(&len_bytes).await { + warn!("[interserver send {:?}] failed: {:?}", server_id, err); + break; + } + if let Err(err) = socket.write_all(payload.as_bytes()).await { + warn!("[interserver send {:?}] failed: {:?}", server_id, err); + break; + } + } + } +} + +pub async fn run_interserver_listen(mut state: STATE, port: u16) +where + STATE: InterserverActor + Send + 'static, + S: serde::Serialize + Debug + Send + 'static, + R: serde::de::DeserializeOwned + Debug + Send, + E: Debug + Send, +{ + let listener = async_std::net::TcpListener::bind(&std::net::SocketAddr::from((std::net::Ipv4Addr::new(0,0,0,0), port))).await.unwrap(); + let mut id = 0; + let ships = Arc::new(RwLock::new(HashMap::new())); + + loop { + let (socket, addr) = listener.accept().await.unwrap(); + info!("[interserver listen] new server: {:?} {:?}", socket, addr); + + id += 1; + let server_id = crate::common::interserver::ServerId(id); + let (client_tx, client_rx) = async_std::channel::unbounded(); + + //let sclient_tx = client_tx.clone(); + /* + state.set_sender(server_id, Arc::new(Box::new(move |msg| { + let sclient_tx = sclient_tx.clone(); + Box::new(async move { + sclient_tx.send(msg).await; + })}))); + */ + state.set_sender(server_id, client_tx.clone()); + + ships + .write() + .await + .insert(server_id, client_tx.clone()); + + for msg in state.on_connect(server_id).await { + if let Some(ship_sender) = ships.read().await.get(&msg.0) { + ship_sender.send(msg.1).await; + } + } + + let rstate = state.clone(); + let rsocket = socket.clone(); + let rships = ships.clone(); + async_std::task::spawn(async move { + interserver_recv_loop(rstate, server_id, rsocket, rships).await; + }); + async_std::task::spawn(async move { + interserver_send_loop(server_id, socket, client_rx).await; + }); + } +} + +pub async fn run_interserver_connect(mut state: STATE, ip: std::net::Ipv4Addr, port: u16) +where + STATE: InterserverActor + Send + 'static, + S: serde::Serialize + Debug + Send + 'static, + R: serde::de::DeserializeOwned + Debug + Send, + E: Debug + Send, +{ + let mut id = 0; + + loop { + info!("[interserver connect] trying to connect to server"); + let socket = match async_std::net::TcpStream::connect((ip, port)).await { + Ok(socket) => socket, + Err(err) => { + info!("err trying to connect to loginserv {:?}", err); + async_std::task::sleep(std::time::Duration::from_secs(10)).await; + continue; + } + }; + id += 1; + let server_id = crate::common::interserver::ServerId(id); + info!("[interserver connect] found loginserv: {:?} {:?}", server_id, socket); + + let (client_tx, client_rx) = async_std::channel::unbounded(); + + state.set_sender(server_id, client_tx.clone()); + /* + let sclient_tx = client_tx.clone(); + state.set_sender(server_id, Arc::new(Box::new(move |msg| { + let sclient_tx = sclient_tx.clone(); + Box::new(async move { + sclient_tx.send(msg).await; + })}))); + */ + + let other_server = vec![(server_id, client_tx.clone())].into_iter().collect(); + + let rstate = state.clone(); + let rsocket = socket.clone(); + async_std::task::spawn(async move { + interserver_recv_loop(rstate, server_id, rsocket, Arc::new(RwLock::new(other_server))).await; + }); + let ssocket = socket.clone(); + async_std::task::spawn(async move { + interserver_send_loop(server_id, ssocket, client_rx).await; + }); + + let mut buf = [0u8; 1]; + loop { + let peek = socket.peek(&mut buf).await; + match peek { + Ok(len) if len == 0 => { + break + }, + _ => { + } + } + } + } + +} diff --git a/src/common/serverstate.rs b/src/common/serverstate.rs index 4d272ce..8f14d3a 100644 --- a/src/common/serverstate.rs +++ b/src/common/serverstate.rs @@ -4,9 +4,10 @@ use libpso::crypto::PSOCipher; #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, derive_more::Display)] pub struct ClientId(pub usize); -pub enum OnConnect { +pub enum OnConnect { Packet(S), - Cipher((Box, Box)), + Cipher(C, C), + //Cipher((Box, Box)), } pub trait RecvServerPacket: Sized + Sync { @@ -19,14 +20,14 @@ pub trait SendServerPacket: Sized + Sync { // TODO: rename this trait, this isn't the state but the actionability of the state re: the client #[async_trait::async_trait] -pub trait ServerState { +pub trait ServerState: Clone { type SendPacket: SendServerPacket; type RecvPacket: RecvServerPacket; + type Cipher: PSOCipher; type PacketError; - async fn on_connect(&mut self, id: ClientId) -> Result>, Self::PacketError>; - async fn handle(&mut self, id: ClientId, pkt: &Self::RecvPacket) - -> Result + Send>, Self::PacketError>; + async fn on_connect(&mut self, id: ClientId) -> Result>, Self::PacketError>; + async fn handle(&mut self, id: ClientId, pkt: Self::RecvPacket) -> Result, Self::PacketError>; + //-> Result>, Self::PacketError>; async fn on_disconnect(&mut self, id: ClientId) -> Result, Self::PacketError>; } - diff --git a/src/lib.rs b/src/lib.rs index 47c688a..068f6e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,8 +4,9 @@ #![feature(try_blocks)] #![feature(once_cell)] #![feature(pin_macro)] +#![feature(test)] - +extern crate test; extern crate fix_hidden_lifetime_bug; diff --git a/src/login/character.rs b/src/login/character.rs index 63bd8bc..109681b 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -2,6 +2,9 @@ use std::io::Read; use std::collections::{BTreeMap, BTreeSet, HashMap}; +use async_std::sync::Arc; +use async_std::channel; + use rand::Rng; use crc::{crc32, Hasher32}; @@ -15,7 +18,7 @@ use libpso::character::character; use crate::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; use crate::common::interserver::{ServerId, InterserverActor, LoginMessage, ShipMessage, Ship}; -use crate::common::leveltable::CharacterLevelTable; +use crate::common::leveltable::LEVEL_TABLE; use libpso::{utf8_to_array, utf8_to_utf16_array}; use crate::entity::gateway::{EntityGateway, GatewayError}; @@ -179,22 +182,24 @@ struct ConnectedClient { expires: Option>, } -pub struct CharacterServerState { +#[derive(Clone)] +pub struct CharacterServerState { entity_gateway: EG, param_header: ParamDataHeader, param_data: Vec, clients: HashMap, ships: BTreeMap, - level_table: CharacterLevelTable, + //level_table: CharacterLevelTable, auth_token: AuthToken, connected_clients: BTreeMap, authenticated_ships: BTreeSet, - ship_sender: BTreeMap>, + //ship_sender: BTreeMap Box> + Send>>>, + ship_sender: BTreeMap>, } -async fn new_character(entity_gateway: &mut EG, user: &UserAccountEntity, preview: &CharacterPreview) -> Result<(), anyhow::Error> { +async fn new_character(entity_gateway: &mut EG, user: &UserAccountEntity, preview: &CharacterPreview) -> Result<(), anyhow::Error> { let mut character = new_character_from_preview(user, preview); match character.char_class { CharacterClass::FOmar | CharacterClass::FOmarl| CharacterClass::FOnewm | CharacterClass::FOnewearl => character.techs.set_tech(Technique::Foie, TechLevel(1)), @@ -306,7 +311,7 @@ async fn new_character(entity_gateway: &mut EG, user: &UserAc } -impl CharacterServerState { +impl CharacterServerState { pub fn new(entity_gateway: EG, auth_token: AuthToken) -> CharacterServerState { let (param_header, param_data) = generate_param_data("data/param/"); @@ -316,7 +321,7 @@ impl CharacterServerState { param_data, clients: HashMap::new(), ships: BTreeMap::new(), - level_table: CharacterLevelTable::default(), + //level_table: CharacterLevelTable::default(), auth_token, authenticated_ships: BTreeSet::new(), ship_sender: BTreeMap::new(), @@ -324,10 +329,6 @@ impl CharacterServerState { } } - pub fn set_sender(&mut self, server_id: ServerId, sender: Box) { - self.ship_sender.insert(server_id, sender); - } - async fn validate_login(&mut self, id: ClientId, pkt: &Login) -> Result, anyhow::Error> { match get_login_status(&mut self.entity_gateway, pkt).await { Ok(user) => { @@ -404,7 +405,7 @@ impl CharacterServerState { if select.reason == 0 { let chars = client.characters.as_ref().unwrap(); Ok(if let Some(char) = &chars[select.slot as usize] { - let (level, _stats) = self.level_table.get_stats_from_exp(char.char_class, char.exp); + let (level, _stats) = LEVEL_TABLE.get_stats_from_exp(char.char_class, char.exp); vec![SendCharacterPacket::CharacterPreview(CharacterPreview { slot: select.slot, character: SelectScreenCharacterBuilder::new() @@ -552,12 +553,13 @@ impl CharacterServerState { } #[async_trait::async_trait] -impl ServerState for CharacterServerState { +impl ServerState for CharacterServerState { type SendPacket = SendCharacterPacket; type RecvPacket = RecvCharacterPacket; + type Cipher = PSOBBCipher; type PacketError = anyhow::Error; - async fn on_connect(&mut self, id: ClientId) -> Result>, anyhow::Error> { + async fn on_connect(&mut self, id: ClientId) -> Result>, anyhow::Error> { self.clients.insert(id, ClientState::new()); let mut rng = rand::thread_rng(); @@ -568,56 +570,57 @@ impl ServerState for CharacterServerState { rng.fill(&mut client_key[..]); Ok(vec![OnConnect::Packet(SendCharacterPacket::LoginWelcome(LoginWelcome::new(server_key, client_key))), - OnConnect::Cipher((Box::new(PSOBBCipher::new(ELSEWHERE_PARRAY, ELSEWHERE_PRIVATE_KEY, client_key)), - Box::new(PSOBBCipher::new(ELSEWHERE_PARRAY, ELSEWHERE_PRIVATE_KEY, server_key)))) + OnConnect::Cipher(PSOBBCipher::new(ELSEWHERE_PARRAY, ELSEWHERE_PRIVATE_KEY, client_key), + PSOBBCipher::new(ELSEWHERE_PARRAY, ELSEWHERE_PRIVATE_KEY, server_key)) + //OnConnect::Cipher((Box::new(PSOBBCipher::new(ELSEWHERE_PARRAY, ELSEWHERE_PRIVATE_KEY, client_key)), + // Box::new(PSOBBCipher::new(ELSEWHERE_PARRAY, ELSEWHERE_PRIVATE_KEY, server_key)))) ]) } - async fn handle(&mut self, id: ClientId, pkt: &RecvCharacterPacket) - -> Result + Send>, anyhow::Error> { + async fn handle(&mut self, id: ClientId, pkt: RecvCharacterPacket) -> Result, anyhow::Error> { Ok(match pkt { RecvCharacterPacket::Login(login) => { if login.session.action == SessionAction::SelectCharacter { - Box::new(self.send_ship_list(id, login)?.into_iter().map(move |pkt| (id, pkt))) + self.send_ship_list(id, &login)?.into_iter().map(move |pkt| (id, pkt)).collect() } else { - Box::new(self.validate_login(id, login).await?.into_iter().map(move |pkt| (id, pkt))) + self.validate_login(id, &login).await?.into_iter().map(move |pkt| (id, pkt)).collect() } }, RecvCharacterPacket::RequestSettings(_req) => { - Box::new(self.get_settings(id).await?.into_iter().map(move |pkt| (id, pkt))) + self.get_settings(id).await?.into_iter().map(move |pkt| (id, pkt)).collect() }, RecvCharacterPacket::CharSelect(sel) => { - Box::new(self.char_select(id, sel).await?.into_iter().map(move |pkt| (id, pkt))) + self.char_select(id, &sel).await?.into_iter().map(move |pkt| (id, pkt)).collect() }, RecvCharacterPacket::Checksum(_checksum) => { - Box::new(self.validate_checksum().into_iter().map(move |pkt| (id, pkt))) + self.validate_checksum().into_iter().map(move |pkt| (id, pkt)).collect() }, RecvCharacterPacket::GuildcardDataRequest(_request) => { - Box::new(self.guildcard_data_header(id).await?.into_iter().map(move |pkt| (id, pkt))) + self.guildcard_data_header(id).await?.into_iter().map(move |pkt| (id, pkt)).collect() }, RecvCharacterPacket::GuildcardDataChunkRequest(request) => { - Box::new(self.guildcard_data_chunk(id, request.chunk, request.again)?.into_iter().map(move |pkt| (id, pkt))) + self.guildcard_data_chunk(id, request.chunk, request.again)?.into_iter().map(move |pkt| (id, pkt)).collect() }, RecvCharacterPacket::ParamDataRequest(_request) => { - Box::new(vec![SendCharacterPacket::ParamDataHeader(self.param_header.clone())].into_iter().map(move |pkt| (id, pkt))) + vec![SendCharacterPacket::ParamDataHeader(self.param_header.clone())].into_iter().map(move |pkt| (id, pkt)).collect() }, RecvCharacterPacket::SetFlag(flag) => { - Box::new(self.set_flag(id, flag).await?.map(move |pkt| (id, pkt))) + self.set_flag(id, &flag).await?.map(move |pkt| (id, pkt)).collect() }, RecvCharacterPacket::ParamDataChunkRequest(request) => { - Box::new(self.param_data_chunk_request(id, request)?.into_iter().map(move |pkt| (id, pkt))) + self.param_data_chunk_request(id, &request)?.into_iter().map(move |pkt| (id, pkt)).collect() }, RecvCharacterPacket::CharacterPreview(preview) => { - Box::new(self.character_preview(id, preview).await?.into_iter().map(move |pkt| (id, pkt))) + self.character_preview(id, &preview).await?.into_iter().map(move |pkt| (id, pkt)).collect() }, RecvCharacterPacket::MenuSelect(menuselect) => { - Box::new(self.select_ship(id, menuselect)?.into_iter().map(move |pkt| (id, pkt))) + self.select_ship(id, &menuselect)?.into_iter().map(move |pkt| (id, pkt)).collect() }, RecvCharacterPacket::MenuDetail(menudetail) => { match menudetail.menu { - SHIP_MENU_ID => Box::new(self.ship_detail(menudetail)?.into_iter().map(move |pkt| (id, pkt))), - _ => Box::new(Vec::new().into_iter()) + SHIP_MENU_ID => self.ship_detail(&menudetail)?.into_iter().map(move |pkt| (id, pkt)).collect(), + _ => Vec::new() } } }) @@ -634,7 +637,7 @@ impl ServerState for CharacterServerState { } #[async_trait::async_trait] -impl InterserverActor for CharacterServerState { +impl InterserverActor for CharacterServerState { type SendMessage = LoginMessage; type RecvMessage = ShipMessage; type Error = (); @@ -643,7 +646,7 @@ impl InterserverActor for CharacterServerState { Vec::new() } - async fn action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result, Self::Error> { + async fn on_action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result, Self::Error> { match msg { ShipMessage::Authenticate(auth_token) => { if self.auth_token == auth_token { @@ -711,6 +714,10 @@ impl InterserverActor for CharacterServerState { .collect(); Vec::new() } + + fn set_sender(&mut self, server_id: ServerId, sender: channel::Sender) { + self.ship_sender.insert(server_id, sender); + } } @@ -840,9 +847,7 @@ mod test { }); server.clients.insert(ClientId(5), clientstate); - let send = server.handle(ClientId(5), &RecvCharacterPacket::RequestSettings(RequestSettings{})).await - .unwrap() - .collect::>(); + let send = server.handle(ClientId(5), RecvCharacterPacket::RequestSettings(RequestSettings{})).await.unwrap(); assert!(send.len() == 1); assert!(send[0].0 == ClientId(5)); @@ -857,9 +862,9 @@ mod test { struct TestData; impl EntityGateway for TestData {} let mut server = CharacterServerState::new(TestData {}, AuthToken("".into())); - let send = server.handle(ClientId(1), &RecvCharacterPacket::Checksum(Checksum {checksum: 1234, - padding: 0, - })).await.unwrap().collect::>(); + let send = server.handle(ClientId(1), RecvCharacterPacket::Checksum(Checksum {checksum: 1234, + padding: 0, + })).await.unwrap(); assert!(send.len() == 1); let bytes = send[0].1.as_bytes(); @@ -888,9 +893,9 @@ mod test { let mut server = CharacterServerState::new(test_data.clone(), AuthToken("".into())); server.clients.insert(ClientId(1), fake_user.clone()); - let mut send = server.handle(ClientId(1), &RecvCharacterPacket::SetFlag(SetFlag {flags: 1})).await.unwrap().collect::>(); + let mut send = server.handle(ClientId(1), RecvCharacterPacket::SetFlag(SetFlag {flags: 1})).await.unwrap(); assert!(test_data.get_user_by_id(UserAccountId(3)).await.unwrap().flags == 1); - send = server.handle(ClientId(1), &RecvCharacterPacket::CharacterPreview(CharacterPreview {slot: 1, character: character::SelectScreenCharacter { + send = server.handle(ClientId(1), RecvCharacterPacket::CharacterPreview(CharacterPreview {slot: 1, character: character::SelectScreenCharacter { exp: 0, level: 0, guildcard: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], @@ -916,7 +921,7 @@ mod test { prop_y: 0.0, name: [9, 69, 116, 101, 115, 116, 32, 110, 97, 109, 101, 0, 0, 0, 0, 0], // "\tEtest name" play_time: 0, - } })).await.unwrap().collect::>(); + } })).await.unwrap(); assert!(send.len() == 2); let chars = test_data.get_characters_by_user(&fake_user.user.unwrap()).await.unwrap(); diff --git a/src/login/login.rs b/src/login/login.rs index 6d73817..5b2ce52 100644 --- a/src/login/login.rs +++ b/src/login/login.rs @@ -93,13 +93,14 @@ pub fn check_if_already_online(user: UserAccountEntity) -> Result { +#[derive(Clone)] +pub struct LoginServerState { character_server_ip: net::Ipv4Addr, entity_gateway: EG, clients: HashMap, } -impl LoginServerState { +impl LoginServerState { pub fn new(entity_gateway: EG, character_server_ip: net::Ipv4Addr) -> LoginServerState { LoginServerState { entity_gateway, @@ -128,13 +129,14 @@ impl LoginServerState { } #[async_trait::async_trait] -impl ServerState for LoginServerState { +impl ServerState for LoginServerState { type SendPacket = SendLoginPacket; type RecvPacket = RecvLoginPacket; + type Cipher = PSOBBCipher; //type PacketError = LoginError; type PacketError = anyhow::Error; - async fn on_connect(&mut self, _id: ClientId) -> Result>, anyhow::Error> { + async fn on_connect(&mut self, _id: ClientId) -> Result>, anyhow::Error> { let mut rng = rand::thread_rng(); let mut server_key = [0u8; 48]; @@ -143,20 +145,20 @@ impl ServerState for LoginServerState { rng.fill(&mut client_key[..]); Ok(vec![OnConnect::Packet(SendLoginPacket::LoginWelcome(LoginWelcome::new(server_key, client_key))), - OnConnect::Cipher((Box::new(PSOBBCipher::new(ELSEWHERE_PARRAY, ELSEWHERE_PRIVATE_KEY, client_key)), - Box::new(PSOBBCipher::new(ELSEWHERE_PARRAY, ELSEWHERE_PRIVATE_KEY, server_key)))) + OnConnect::Cipher(PSOBBCipher::new(ELSEWHERE_PARRAY, ELSEWHERE_PRIVATE_KEY, client_key), + PSOBBCipher::new(ELSEWHERE_PARRAY, ELSEWHERE_PRIVATE_KEY, server_key)) ]) } - async fn handle(&mut self, id: ClientId, pkt: &Self::RecvPacket) - -> Result + Send>, anyhow::Error> { + async fn handle(&mut self, id: ClientId, pkt: Self::RecvPacket) -> Result, anyhow::Error> { Ok(match pkt { RecvLoginPacket::Login(login) => { - Box::new(self.validate_login(id, login).await? - .into_iter() - .map(move |pkt| { - (id, pkt) - })) + self.validate_login(id, &login).await? + .into_iter() + .map(move |pkt| { + (id, pkt) + }) + .collect() } }) } @@ -237,7 +239,7 @@ mod test { let mut server = LoginServerState::new(TestData {}, "127.0.0.1".parse().unwrap()); - let send = server.handle(ClientId(1), &LOGIN_PACKET).await.unwrap().collect::>(); + let send = server.handle(ClientId(1), LOGIN_PACKET).await.unwrap(); assert!(send == vec![ (ClientId(1), SendLoginPacket::LoginResponse(LoginResponse { status: AccountStatus::Ok, @@ -275,7 +277,7 @@ mod test { } let mut server = LoginServerState::new(TestData {}, "127.0.0.1".parse().unwrap()); - let send = server.handle(ClientId(1), &LOGIN_PACKET).await.unwrap().collect::>(); + let send = server.handle(ClientId(1), LOGIN_PACKET).await.unwrap(); assert!(send == vec![ (ClientId(1), SendLoginPacket::LoginResponse(LoginResponse { @@ -324,7 +326,7 @@ mod test { } let mut server = LoginServerState::new(TestData {}, "127.0.0.1".parse().unwrap()); - let send = server.handle(ClientId(1), &LOGIN_PACKET).await.unwrap().collect::>(); + let send = server.handle(ClientId(1), LOGIN_PACKET).await.unwrap(); assert!(send == vec![ (ClientId(1), SendLoginPacket::LoginResponse(LoginResponse { @@ -373,7 +375,7 @@ mod test { } let mut server = LoginServerState::new(TestData {}, "127.0.0.1".parse().unwrap()); - let send = server.handle(ClientId(1), &LOGIN_PACKET).await.unwrap().collect::>(); + let send = server.handle(ClientId(1), LOGIN_PACKET).await.unwrap(); assert!(send == vec![ (ClientId(1), SendLoginPacket::LoginResponse(LoginResponse { diff --git a/src/patch/patch.rs b/src/patch/patch.rs index 52dd7d2..a7b0715 100644 --- a/src/patch/patch.rs +++ b/src/patch/patch.rs @@ -136,6 +136,7 @@ impl SendServerPacket for SendPatchPacket { } +#[derive(Clone)] pub struct PatchServerState { patch_file_tree: PatchFileTree, patch_file_lookup: HashMap, @@ -158,33 +159,40 @@ impl PatchServerState { impl ServerState for PatchServerState { type SendPacket = SendPatchPacket; type RecvPacket = RecvPatchPacket; + type Cipher = PSOPCCipher; type PacketError = PatchError; - async fn on_connect(&mut self, _id: ClientId) -> Result>, PatchError> { + async fn on_connect(&mut self, _id: ClientId) -> Result>, PatchError> { let mut rng = rand::thread_rng(); let key_in: u32 = rng.gen(); let key_out: u32 = rng.gen(); Ok(vec![OnConnect::Packet(SendPatchPacket::PatchWelcome(PatchWelcome::new(key_out, key_in))), - OnConnect::Cipher((Box::new(PSOPCCipher::new(key_in)), Box::new(PSOPCCipher::new(key_out)))) + OnConnect::Cipher(PSOPCCipher::new(key_in), PSOPCCipher::new(key_out)) ]) } - async fn handle(&mut self, id: ClientId, pkt: &RecvPatchPacket) - -> Result + Send>, PatchError> { + async fn handle(&mut self, id: ClientId, pkt: RecvPatchPacket) -> Result, PatchError> { Ok(match pkt { RecvPatchPacket::PatchWelcomeReply(_pkt) => { - Box::new(vec![SendPatchPacket::RequestLogin(RequestLogin {})].into_iter().map(move |pkt| (id, pkt))) + vec![SendPatchPacket::RequestLogin(RequestLogin {})] + .into_iter() + .map(move |pkt| (id, pkt)) + .collect() }, RecvPatchPacket::LoginReply(_pkt) => { - let mut p = vec![SendPatchPacket::Message(Message::new(self.patch_motd.clone()))]; - p.append(&mut get_file_list_packets(&self.patch_file_tree)); - p.push(SendPatchPacket::PatchEndList(PatchEndList {})); - Box::new(p.into_iter().map(move |pkt| (id, pkt))) + let mut pkts = vec![SendPatchPacket::Message(Message::new(self.patch_motd.clone()))]; + pkts.append(&mut get_file_list_packets(&self.patch_file_tree)); + pkts.push(SendPatchPacket::PatchEndList(PatchEndList {})); + pkts + .into_iter() + .map(move |pkt| (id, pkt)) + .collect() }, RecvPatchPacket::FileInfoReply(pkt) => { self.patch_file_info.push(pkt.clone()); - Box::new(None.into_iter().map(move |pkt| (id, pkt))) + Vec::new() + //None.into_iter().map(move |pkt| (id, pkt)) }, RecvPatchPacket::FileInfoListEnd(_pkt) => { let need_update = self.patch_file_info.iter() @@ -194,10 +202,12 @@ impl ServerState for PatchServerState { let total_size = need_update.iter().fold(0, |a, file_info| a + file_info.size); let total_files = need_update.len() as u32; - let p = vec![SendPatchPacket::FilesToPatchMetadata(FilesToPatchMetadata::new(total_size, total_files)), - SendPatchPacket::PatchStartList(PatchStartList {}) - ]; - Box::new(p.into_iter().chain(SendFileIterator::new(self)).map(move |pkt| (id, pkt))) + vec![SendPatchPacket::FilesToPatchMetadata(FilesToPatchMetadata::new(total_size, total_files)), + SendPatchPacket::PatchStartList(PatchStartList {})] + .into_iter() + .chain(SendFileIterator::new(self)) + .map(move |pkt| (id, pkt)) + .collect() } }) } diff --git a/src/ship/items/actions.rs b/src/ship/items/actions.rs index 8d4b2ba..541077c 100644 --- a/src/ship/items/actions.rs +++ b/src/ship/items/actions.rs @@ -29,9 +29,9 @@ pub(super) fn take_item_from_floor(character_id: CharacterEntityId, item_id: Cli { move |(mut item_state, transaction): (ItemStateProxy<'_>, Box) , _| { Box::pin(async move { - let mut floor = item_state.floor(&character_id)?; + let mut floor = item_state.floor(&character_id).await?; let item = floor.take_item(&item_id).ok_or(ItemStateError::NoFloorItem(item_id))?; - item_state.set_floor(floor); + item_state.set_floor(floor).await; Ok(((item_state, transaction), item)) }) @@ -46,7 +46,7 @@ pub(super) fn add_floor_item_to_inventory(character: &CharacterEntity) move |(mut item_state, transaction), floor_item| { let character = character.clone(); Box::pin(async move { - let mut inventory = item_state.inventory(&character.id)?; + let mut inventory = item_state.inventory(&character.id).await?; let character_id = character.id; let transaction = floor_item.with_entity_id(transaction, |mut transaction, entity_id| { @@ -87,7 +87,7 @@ pub(super) fn take_item_from_inventory(character_id: CharacterEntityId, item_id: { move |(mut item_state, mut transaction), _| { Box::pin(async move { - let mut inventory = item_state.inventory(&character_id)?; + let mut inventory = item_state.inventory(&character_id).await?; let item = inventory.take_item(&item_id, amount).ok_or (ItemStateError::NoFloorItem(item_id))?; transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?; @@ -117,9 +117,9 @@ pub(super) fn add_inventory_item_to_shared_floor(character_id: CharacterEntityId Ok(transaction) }}).await?; - let mut floor = item_state.floor(&character_id)?; + let mut floor = item_state.floor(&character_id).await?; let floor_item = floor.add_inventory_item(inventory_item, map_area, drop_position).clone(); - item_state.set_floor(floor); + item_state.set_floor(floor).await; Ok(((item_state, transaction), floor_item)) }) @@ -133,7 +133,7 @@ pub(super) fn take_meseta_from_inventory(character_id: CharacterEntityId, amount { move |(mut item_state, mut transaction), _| { Box::pin(async move { - let mut inventory = item_state.inventory(&character_id)?; + let mut inventory = item_state.inventory(&character_id).await?; inventory.remove_meseta(amount)?; transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?; item_state.set_inventory(inventory); @@ -149,7 +149,7 @@ pub(super) fn add_meseta_to_inventory(character_id: CharacterEntityId, amount: u { move |(mut item_state, mut transaction), _| { Box::pin(async move { - let mut inventory = item_state.inventory(&character_id)?; + let mut inventory = item_state.inventory(&character_id).await?; inventory.add_meseta(amount)?; transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?; item_state.set_inventory(inventory); @@ -167,7 +167,7 @@ pub(super) fn add_meseta_to_shared_floor(character_id: CharacterEntityId, amount move |(mut item_state, transaction), _| { Box::pin(async move { let floor_item = FloorItem { - item_id: item_state.new_item_id()?, + item_id: item_state.new_item_id().await?, item: FloorItemDetail::Meseta(Meseta(amount)), map_area, x: drop_position.0, @@ -175,9 +175,9 @@ pub(super) fn add_meseta_to_shared_floor(character_id: CharacterEntityId, amount z: drop_position.1, }; - let mut floor = item_state.floor(&character_id)?; + let mut floor = item_state.floor(&character_id).await?; let floor_item = floor.add_shared_item(floor_item).clone(); - item_state.set_floor(floor); + item_state.set_floor(floor).await; Ok(((item_state, transaction), floor_item)) }) @@ -190,7 +190,7 @@ pub(super) fn take_meseta_from_bank(character_id: CharacterEntityId, amount: u32 { move |(mut item_state, mut transaction), _| { Box::pin(async move { - let mut bank = item_state.bank(&character_id)?; + let mut bank = item_state.bank(&character_id).await?; bank.remove_meseta(amount)?; transaction.gateway().set_bank_meseta(&character_id, &bank.name, bank.meseta).await?; @@ -205,7 +205,7 @@ pub(super) fn add_meseta_from_bank_to_inventory(character_id: CharacterEntityId, { move |(mut item_state, mut transaction), _| { Box::pin(async move { - let mut inventory = item_state.inventory(&character_id)?; + let mut inventory = item_state.inventory(&character_id).await?; inventory.add_meseta_no_overflow(amount)?; transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?; @@ -221,7 +221,7 @@ pub(super) fn add_meseta_to_bank(character_id: CharacterEntityId, amount: u32) { move |(mut item_state, mut transaction), _| { Box::pin(async move { - let mut bank = item_state.bank(&character_id)?; + let mut bank = item_state.bank(&character_id).await?; bank.add_meseta(amount)?; transaction.gateway().set_bank_meseta(&character_id, &bank.name, bank.meseta).await?; @@ -237,7 +237,7 @@ pub(super) fn take_item_from_bank(character_id: CharacterEntityId, item_id: Clie { move |(mut item_state, mut transaction), _| { Box::pin(async move { - let mut bank = item_state.bank(&character_id)?; + let mut bank = item_state.bank(&character_id).await?; let item = bank.take_item(&item_id, amount).ok_or(ItemStateError::NoBankItem(item_id))?; transaction.gateway().set_character_bank(&character_id, &bank.as_bank_entity(), &bank.name).await?; item_state.set_bank(bank); @@ -255,8 +255,8 @@ pub(super) fn add_bank_item_to_inventory(character: &CharacterEntity) move |(mut item_state, transaction), bank_item| { let character = character.clone(); Box::pin(async move { - let bank_name = item_state.bank(&character.id)?.name; - let mut inventory = item_state.inventory(&character.id)?; + let bank_name = item_state.bank(&character.id).await?.name; + let mut inventory = item_state.inventory(&character.id).await?; let character_id = character.id; let transaction = bank_item.with_entity_id(transaction, |mut transaction, entity_id| { @@ -300,7 +300,7 @@ pub(super) fn add_inventory_item_to_bank(character_id: CharacterEntityId) { move |(mut item_state, transaction), inventory_item| { Box::pin(async move { - let mut bank = item_state.bank(&character_id)?; + let mut bank = item_state.bank(&character_id).await?; let bank_name = bank.name.clone(); let mut transaction = inventory_item.with_entity_id(transaction, move |mut transaction, entity_id| { let bank_name = bank_name.clone(); @@ -330,7 +330,7 @@ pub(super) fn equip_inventory_item(character_id: CharacterEntityId, item_id: Cli { move |(mut item_state, mut transaction), _| { Box::pin(async move { - let mut inventory = item_state.inventory(&character_id)?; + let mut inventory = item_state.inventory(&character_id).await?; inventory.equip(&item_id, equip_slot); transaction.gateway().set_character_equips(&character_id, &inventory.as_equipped_entity()).await?; item_state.set_inventory(inventory); @@ -347,7 +347,7 @@ pub(super) fn unequip_inventory_item(character_id: CharacterEntityId, item_id: C { move |(mut item_state, mut transaction), _| { Box::pin(async move { - let mut inventory = item_state.inventory(&character_id)?; + let mut inventory = item_state.inventory(&character_id).await?; inventory.unequip(&item_id); transaction.gateway().set_character_equips(&character_id, &inventory.as_equipped_entity()).await?; item_state.set_inventory(inventory); @@ -366,7 +366,7 @@ pub(super) fn sort_inventory_items(character_id: CharacterEntityId, item_ids: Ve move |(mut item_state, mut transaction), _| { let item_ids = item_ids.clone(); Box::pin(async move { - let mut inventory = item_state.inventory(&character_id)?; + let mut inventory = item_state.inventory(&character_id).await?; inventory.sort(&item_ids); transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?; item_state.set_inventory(inventory); @@ -405,7 +405,7 @@ pub(super) fn feed_mag_item(character: CharacterEntity, mag_item_id: ClientItemI move |(mut item_state, transaction), tool| { let character = character.clone(); Box::pin(async move { - let mut inventory = item_state.inventory(&character.id)?; + let mut inventory = item_state.inventory(&character.id).await?; let mag_entity = inventory.get_by_client_id_mut(&mag_item_id) .ok_or(ItemStateError::InvalidItemId(mag_item_id))? .item @@ -454,7 +454,7 @@ pub(super) fn add_bought_item_to_inventory<'a>(character_id: CharacterEntityId, { move |(mut item_state, mut transaction), _| { Box::pin(async move { - let mut inventory = item_state.inventory(&character_id)?; + let mut inventory = item_state.inventory(&character_id).await?; let bought_item = shop_item.as_item(); let inventory_item = match bought_item { @@ -512,7 +512,7 @@ pub(super) fn sell_inventory_item<'a>(character_id: CharacterEntityId) { move |(mut item_state, transaction), inventory_item| { Box::pin(async move { - let mut inventory = item_state.inventory(&character_id)?; + let mut inventory = item_state.inventory(&character_id).await?; let price = inventory_item.item.sell_price()?; inventory.add_meseta_no_overflow(price)?; @@ -648,7 +648,7 @@ pub(super) fn add_item_to_inventory(character: CharacterEntity) move |(mut item_state, transaction), inventory_item| { let character = character.clone(); Box::pin(async move { - let mut inventory = item_state.inventory(&character.id)?; + let mut inventory = item_state.inventory(&character.id).await?; let mut transaction = inventory_item.with_mag(transaction, |mut transaction, entity_id, _mag| { let character = character.clone(); async move { @@ -694,7 +694,7 @@ pub(super) fn assign_new_item_id() { move |(mut item_state, transaction), mut inventory_item| { Box::pin(async move { - inventory_item.item_id = item_state.new_item_id()?; + inventory_item.item_id = item_state.new_item_id().await?; Ok(((item_state, transaction), inventory_item)) }) } @@ -732,7 +732,7 @@ pub(super) fn convert_item_drop_to_floor_item(character_id: CharacterEntityId, i ItemDropType::Meseta(m) => ItemOrMeseta::Meseta(Meseta(m)), }; - let item_id = item_state.new_item_id()?; + let item_id = item_state.new_item_id().await?; let floor_item = match item { ItemOrMeseta::Individual(item_detail) => { @@ -804,9 +804,9 @@ pub(super) fn add_item_to_local_floor(character_id: CharacterEntityId) { move |(mut item_state, transaction) , floor_item| { Box::pin(async move { - let mut floor = item_state.floor(&character_id)?; + let mut floor = item_state.floor(&character_id).await?; let item = floor.add_local_item(floor_item).clone(); - item_state.set_floor(floor); + item_state.set_floor(floor).await; Ok(((item_state, transaction), item)) }) diff --git a/src/ship/items/apply_item.rs b/src/ship/items/apply_item.rs index d43f55d..598678f 100644 --- a/src/ship/items/apply_item.rs +++ b/src/ship/items/apply_item.rs @@ -107,7 +107,7 @@ async fn mag_cell<'a, EG>(item_state: &mut ItemStateProxy<'a>, where EG: EntityGateway + ?Sized, { - let mut inventory = item_state.inventory(&character.id)?; + let mut inventory = item_state.inventory(&character.id).await?; let (mag_entity_id, mag) = inventory.equipped_mag_mut() .ok_or(ApplyItemError::ItemNotEquipped)?; diff --git a/src/ship/items/state.rs b/src/ship/items/state.rs index a17da5f..5341921 100644 --- a/src/ship/items/state.rs +++ b/src/ship/items/state.rs @@ -1,7 +1,12 @@ use std::collections::HashMap; +use async_std::sync::{Arc, RwLock}; use crate::ship::items::ClientItemId; use crate::entity::item::{ItemEntityId, ItemDetail, ItemEntity, InventoryItemEntity, BankItemEntity, BankName}; +use futures::future::join_all; + + + use crate::ship::location::{AreaClient, RoomId}; use crate::entity::character::{CharacterEntity, CharacterEntityId}; use crate::entity::gateway::{EntityGateway, GatewayError}; @@ -141,46 +146,62 @@ pub enum AddItemResult { } +#[derive(Clone)] pub struct ItemState { - character_inventory: HashMap, - character_bank: HashMap, + character_inventory: Arc>>>, + character_bank: Arc>>>, - character_room: HashMap, - character_floor: HashMap, - room_floor: HashMap, + character_room: Arc>>, + character_floor: Arc>>>, + room_floor: Arc>>>, - room_item_id_counter: u32, + room_item_id_counter: Arc>, } impl Default for ItemState { fn default() -> ItemState { ItemState { - character_inventory: HashMap::new(), - character_bank: HashMap::new(), - character_room: HashMap::new(), - character_floor: HashMap::new(), - room_floor: HashMap::new(), - room_item_id_counter: 0x00810000, + character_inventory: Arc::new(RwLock::new(HashMap::new())), + character_bank: Arc::new(RwLock::new(HashMap::new())), + character_room: Arc::new(RwLock::new(HashMap::new())), + character_floor: Arc::new(RwLock::new(HashMap::new())), + room_floor: Arc::new(RwLock::new(HashMap::new())), + room_item_id_counter: Arc::new(RwLock::new(0x00810000)), } } } impl ItemState { - pub fn get_character_inventory(&self, character: &CharacterEntity) -> Result<&InventoryState, ItemStateError> { - self.character_inventory.get(&character.id) - .ok_or(ItemStateError::NoCharacter(character.id)) + pub async fn get_character_inventory(&self, character: &CharacterEntity) -> Result { + Ok(self.character_inventory + .read() + .await + .get(&character.id) + .ok_or(ItemStateError::NoCharacter(character.id))? + .read() + .await + .clone()) } - pub fn get_character_bank(&self, character: &CharacterEntity) -> Result<&BankState, ItemStateError> { - self.character_bank.get(&character.id) - .ok_or(ItemStateError::NoCharacter(character.id)) + pub async fn get_character_bank(&self, character: &CharacterEntity) -> Result { + Ok(self.character_bank + .read() + .await + .get(&character.id) + .ok_or(ItemStateError::NoCharacter(character.id))? + .read() + .await + .clone()) } } impl ItemState { - fn new_item_id(&mut self) -> Result { - self.room_item_id_counter += 1; - Ok(ClientItemId(self.room_item_id_counter)) + async fn new_item_id(&mut self) -> Result { + //self.room_item_id_counter += 1; + *self.room_item_id_counter + .write() + .await += 1; + Ok(ClientItemId(*self.room_item_id_counter.read().await)) } pub async fn load_character(&mut self, entity_gateway: &mut EG, character: &CharacterEntity) -> Result<(), ItemStateError> { @@ -216,7 +237,7 @@ impl ItemState { }, }) }) - .collect::, _>>()?; + .collect::, ItemStateError>>()?; let character_meseta = entity_gateway.get_character_meseta(&character.id).await?; let inventory_state = InventoryState { @@ -226,83 +247,155 @@ impl ItemState { equipped, meseta: character_meseta, }; - - let bank_items = bank.items.into_iter() - .map(|item| -> Result { - Ok(match item { - BankItemEntity::Individual(item) => { - BankItem { - item_id: self.new_item_id()?, - item: BankItemDetail::Individual(IndividualItemDetail { - entity_id: item.id, - item: item.item, - }) - } - }, - BankItemEntity::Stacked(items) => { - BankItem { - item_id: self.new_item_id()?, - item: BankItemDetail::Stacked(StackedItemDetail { - entity_ids: items.iter().map(|i| i.id).collect(), - tool: items.get(0) - .ok_or_else(|| ItemStateError::StackedItemError(items.clone()))? - .item - .clone() - .as_tool() - .ok_or_else(|| ItemStateError::StackedItemError(items.clone()))? - }) - } - }, - }) - }) - .collect::, _>>()?; - + + let bank_items = join_all( + bank.items.into_iter() + .map(|item| { + let mut citem_state = self.clone(); + async move { + Ok(match item { + BankItemEntity::Individual(item) => { + BankItem { + item_id: citem_state.new_item_id().await?, + item: BankItemDetail::Individual(IndividualItemDetail { + entity_id: item.id, + item: item.item, + }) + } + }, + BankItemEntity::Stacked(items) => { + BankItem { + item_id: citem_state.new_item_id().await?, + item: BankItemDetail::Stacked(StackedItemDetail { + entity_ids: items.iter().map(|i| i.id).collect(), + tool: items.get(0) + .ok_or_else(|| ItemStateError::StackedItemError(items.clone()))? + .item + .clone() + .as_tool() + .ok_or_else(|| ItemStateError::StackedItemError(items.clone()))? + }) + } + }, + }) + }}) + .collect::>()) + .await + .into_iter() + .collect::, ItemStateError>>()?; + let bank_meseta = entity_gateway.get_bank_meseta(&character.id, &BankName("".into())).await?; let bank_state = BankState::new(character.id, BankName("".into()), Bank::new(bank_items), bank_meseta); - self.character_inventory.insert(character.id, inventory_state); - self.character_bank.insert(character.id, bank_state); + self.character_inventory + .write() + .await + .insert(character.id, RwLock::new(inventory_state)); + self.character_bank + .write() + .await + .insert(character.id, RwLock::new(bank_state)); Ok(()) } - pub fn add_character_to_room(&mut self, room_id: RoomId, character: &CharacterEntity, area_client: AreaClient) { + pub async fn add_character_to_room(&mut self, room_id: RoomId, character: &CharacterEntity, area_client: AreaClient) { let base_inventory_id = ((area_client.local_client.id() as u32) << 21) | 0x10000; - let inventory = self.character_inventory.get_mut(&character.id).unwrap(); - inventory.initialize_item_ids(base_inventory_id); + //let inventory = self.character_inventory.get_mut(&character.id).unwrap(); + self.character_inventory + .read() + .await + .get(&character.id) + .unwrap() + .write() + .await + .initialize_item_ids(base_inventory_id); + //inventory.initialize_item_ids(base_inventory_id); let base_bank_id = ((area_client.local_client.id() as u32) << 21) | 0x20000; - let default_bank = self.character_bank.get_mut(&character.id); - if let Some(default_bank ) = default_bank { - default_bank.initialize_item_ids(base_bank_id); - } - self.character_room.insert(character.id, room_id); - self.character_floor.insert(character.id, LocalFloor::default()); - self.room_floor.entry(room_id).or_insert_with(SharedFloor::default); + //let default_bank = self.character_bank.get_mut(&character.id); + self.character_bank + .read() + .await + .get(&character.id) + .unwrap() + .write() + .await + .initialize_item_ids(base_bank_id); + //if let Some(default_bank) = default_bank { + //default_bank.initialize_item_ids(base_bank_id); + //} + self.character_room + .write() + .await + .insert(character.id, room_id); + self.character_floor + .write() + .await + .insert(character.id, RwLock::new(LocalFloor::default())); + self.room_floor + .write() + .await + .entry(room_id) + .or_insert_with(Default::default); } - pub fn remove_character_from_room(&mut self, character: &CharacterEntity) { - self.character_inventory.remove(&character.id); - self.character_floor.remove(&character.id); - if let Some(room) = self.character_room.remove(&character.id).as_ref() { - if self.character_room.iter().any(|(_, r)| r == room) { - self.room_floor.remove(room); + pub async fn remove_character_from_room(&mut self, character: &CharacterEntity) { + self.character_inventory + .write() + .await + .remove(&character.id); + self.character_floor + .write() + .await + .remove(&character.id); + + let removed = { + self.character_room.write().await.remove(&character.id) + }; + + if let Some(room) = removed.as_ref() { + // TODO: this looks wrong, .all(r != room) maybe? + if self.character_room.read().await.iter().any(|(_, r)| r == room) { + self.room_floor + .write() + .await + .remove(room); } } } - pub fn get_floor_item(&self, character_id: &CharacterEntityId, item_id: &ClientItemId) -> Result<(&FloorItem, FloorType), ItemStateError> { - let local_floor = self.character_floor.get(character_id).ok_or(ItemStateError::NoCharacter(*character_id))?; - let room = self.character_room.get(character_id).ok_or(ItemStateError::NoCharacter(*character_id))?; - let shared_floor = self.room_floor.get(room).ok_or(ItemStateError::NoCharacter(*character_id))?; + pub async fn get_floor_item(&self, character_id: &CharacterEntityId, item_id: &ClientItemId) -> Result<(FloorItem, FloorType), ItemStateError> { + let local_floors = self.character_floor + .read() + .await; + let local_floor = local_floors + .get(character_id) + .ok_or(ItemStateError::NoCharacter(*character_id))? + .read() + .await; + let rooms = self.character_room + .read() + .await; + let room = rooms + .get(character_id) + .ok_or(ItemStateError::NoCharacter(*character_id))?; + let shared_floors = self.room_floor + .read() + .await; + let shared_floor = shared_floors + .get(room) + .ok_or(ItemStateError::NoCharacter(*character_id))? + .read() + .await; local_floor.0 .iter() .find(|item| item.item_id == *item_id) - .map(|item| (item, FloorType::Local)) + .map(|item| (item.clone(), FloorType::Local)) .or_else(|| { shared_floor.0 .iter() .find(|item| item.item_id == *item_id) - .map(|item| (item, FloorType::Shared)) + .map(|item| (item.clone(), FloorType::Shared)) }) .ok_or(ItemStateError::NoFloorItem(*item_id)) } @@ -314,7 +407,7 @@ struct ProxiedItemState { character_inventory: HashMap, character_bank: HashMap, - character_room: HashMap, + //character_room: HashMap, character_floor: HashMap, room_floor: HashMap, } @@ -322,27 +415,99 @@ struct ProxiedItemState { pub struct ItemStateProxy<'a> { item_state: &'a mut ItemState, proxied_state: ProxiedItemState, + //_a: std::marker::PhantomData<&'a ()>, // TODO: remove } impl<'a> ItemStateProxy<'a> { - pub fn commit(self) { - self.item_state.character_inventory.extend(self.proxied_state.character_inventory.clone()); - self.item_state.character_bank.extend(self.proxied_state.character_bank.clone()); - self.item_state.character_room.extend(self.proxied_state.character_room.clone()); - self.item_state.character_floor.extend(self.proxied_state.character_floor.clone()); - self.item_state.room_floor.extend(self.proxied_state.room_floor); + pub async fn commit(self) { + + async fn copy_back(master: &Arc>>>, + proxy: HashMap) + where + K: Eq + std::hash::Hash, + { + for (key, value) in proxy { + if let Some(element) = master + .read() + .await + .get(&key) { + *element + .write() + .await = value; + } + } + } + + copy_back(&self.item_state.character_inventory, self.proxied_state.character_inventory).await; + copy_back(&self.item_state.character_bank, self.proxied_state.character_bank).await; + //copy_back(self.item_state.character_room, self.proxied_state.character_room).await; + copy_back(&self.item_state.character_floor, self.proxied_state.character_floor).await; + copy_back(&self.item_state.room_floor, self.proxied_state.room_floor).await; + + + /* + self.item_state.character_inventory + .write() + .await + .extend(self.proxied_state.character_inventory.clone()); + self.item_state.character_bank + .write() + .await + .extend(self.proxied_state.character_bank.clone()); + self.item_state.character_room + .write() + .await + .extend(self.proxied_state.character_room.clone()); + self.item_state.character_floor + .write() + .await + .extend(self.proxied_state.character_floor.clone()); + self.item_state.room_floor + .write() + .await + .extend(self.proxied_state.room_floor); + */ + /* + for (character_id, character_inventory) in self.proxied_state.character_inventory { + if let Some(inventory) = self.item_state.character_inventory + .read() + .await + .get(&character_id) { + *inventory + .write() + .await = character_inventory; + } + } + */ + } } -fn get_or_clone(master: &HashMap, proxy: &mut HashMap, key: K, err: fn(K) -> ItemStateError) -> Result +async fn get_or_clone(master: &Arc>>>, + proxy: &mut HashMap, + key: K, + err: fn(K) -> ItemStateError) -> Result where K: Eq + std::hash::Hash + Copy, V: Clone { + /* let existing_element = master.get(&key).ok_or_else(|| err(key))?; Ok(proxy.entry(key) .or_insert_with(|| existing_element.clone()).clone()) + */ + let existing_element = master + .read() + .await + .get(&key) + .ok_or_else(|| err(key))? + .read() + .await + .clone(); + Ok(proxy.entry(key) + .or_insert_with(|| existing_element) + .clone()) } @@ -351,41 +516,50 @@ impl<'a> ItemStateProxy<'a> { ItemStateProxy { item_state, proxied_state: Default::default(), + //_a: Default::default(), } } - pub fn inventory(&mut self, character_id: &CharacterEntityId) -> Result { - get_or_clone(&self.item_state.character_inventory, &mut self.proxied_state.character_inventory, *character_id, ItemStateError::NoCharacter) + pub async fn inventory(&mut self, character_id: &CharacterEntityId) -> Result { + get_or_clone(&self.item_state.character_inventory, + &mut self.proxied_state.character_inventory, + *character_id, + ItemStateError::NoCharacter).await } pub fn set_inventory(&mut self, inventory: InventoryState) { self.proxied_state.character_inventory.insert(inventory.character_id, inventory); } - pub fn bank(&mut self, character_id: &CharacterEntityId) -> Result { - get_or_clone(&self.item_state.character_bank, &mut self.proxied_state.character_bank, *character_id, ItemStateError::NoCharacter) + pub async fn bank(&mut self, character_id: &CharacterEntityId) -> Result { + get_or_clone(&self.item_state.character_bank, + &mut self.proxied_state.character_bank, + *character_id, + ItemStateError::NoCharacter).await } pub fn set_bank(&mut self, bank: BankState) { self.proxied_state.character_bank.insert(bank.character_id, bank); } - pub fn floor(&mut self, character_id: &CharacterEntityId) -> Result { - let room_id = get_or_clone(&self.item_state.character_room, &mut self.proxied_state.character_room, *character_id, ItemStateError::NoCharacter)?; + pub async fn floor(&mut self, character_id: &CharacterEntityId) -> Result { + //let room_id = get_or_clone(&self.item_state.character_room, &mut self.proxied_state.character_room, *character_id, ItemStateError::NoCharacter)?; + let room_id = *self.item_state.character_room.read().await.get(character_id).unwrap(); Ok(FloorState { character_id: *character_id, - local: get_or_clone(&self.item_state.character_floor, &mut self.proxied_state.character_floor, *character_id, ItemStateError::NoCharacter)?, - shared: get_or_clone(&self.item_state.room_floor, &mut self.proxied_state.room_floor, room_id, ItemStateError::NoRoom)?, + local: get_or_clone(&self.item_state.character_floor, &mut self.proxied_state.character_floor, *character_id, ItemStateError::NoCharacter).await?, + shared: get_or_clone(&self.item_state.room_floor, &mut self.proxied_state.room_floor, room_id, ItemStateError::NoRoom).await?, }) } - pub fn set_floor(&mut self, floor: FloorState) { - let room_id = get_or_clone(&self.item_state.character_room, &mut self.proxied_state.character_room, floor.character_id, ItemStateError::NoCharacter).unwrap(); + pub async fn set_floor(&mut self, floor: FloorState) { + //let room_id = get_or_clone(&self.item_state.character_room, &mut self.proxied_state.character_room, floor.character_id, ItemStateError::NoCharacter).unwrap(); + let room_id = *self.item_state.character_room.read().await.get(&floor.character_id).unwrap(); self.proxied_state.character_floor.insert(floor.character_id, floor.local); self.proxied_state.room_floor.insert(room_id, floor.shared); } - pub fn new_item_id(&mut self) -> Result { - self.item_state.new_item_id() + pub async fn new_item_id(&mut self) -> Result { + self.item_state.new_item_id().await } } diff --git a/src/ship/items/tasks.rs b/src/ship/items/tasks.rs index 4264420..844d116 100644 --- a/src/ship/items/tasks.rs +++ b/src/ship/items/tasks.rs @@ -32,7 +32,7 @@ where .act(actions::add_floor_item_to_inventory(character)) .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, result)) }).await } @@ -55,7 +55,7 @@ where .act(actions::add_inventory_item_to_shared_floor(character.id, map_area, drop_position)) .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, result)) }).await } @@ -79,7 +79,7 @@ where .act(actions::add_inventory_item_to_shared_floor(character.id, map_area, (drop_position.0, 0.0, drop_position.1))) .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, result)) }).await } @@ -104,7 +104,7 @@ where .act(actions::add_meseta_to_shared_floor(character.id, amount, map_area, drop_position)) .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, result)) }).await } @@ -126,7 +126,7 @@ where .act(actions::add_meseta_from_bank_to_inventory(character.id, amount)) .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, result)) }).await } @@ -148,7 +148,7 @@ where .act(actions::add_meseta_to_bank(character.id, amount)) .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, ())) }).await } @@ -173,7 +173,7 @@ where .act(actions::add_bank_item_to_inventory(character)) .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, result)) }).await } @@ -196,7 +196,7 @@ where .act(actions::add_inventory_item_to_bank(character.id)) .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, result)) }).await } @@ -217,7 +217,7 @@ where .act(actions::equip_inventory_item(character.id, *item_id, equip_slot)) .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, result)) }).await } @@ -238,7 +238,7 @@ where .act(actions::unequip_inventory_item(character.id, *item_id)) .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, result)) }).await } @@ -259,7 +259,7 @@ where .act(actions::sort_inventory_items(character.id, item_ids)) .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, result)) }).await } @@ -282,7 +282,7 @@ where .act(actions::use_consumed_item(character.clone())) .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; *character = new_character; Ok((transaction, ())) }).await @@ -306,7 +306,7 @@ where .act(actions::feed_mag_item(character.clone(), *mag_item_id)) .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, ())) }).await } @@ -333,7 +333,7 @@ where .act(actions::add_bought_item_to_inventory(character.id, shop_item, item_id, amount)) .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, result)) }).await } @@ -356,7 +356,7 @@ where .act(actions::sell_inventory_item(character.id)) .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, result)) }).await } @@ -424,7 +424,7 @@ where .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, (p1_new_items, p2_new_items))) }).await } @@ -446,7 +446,7 @@ where .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, ())) }).await } @@ -468,7 +468,7 @@ where .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, floor_item)) }).await } @@ -494,7 +494,7 @@ where .commit((item_state_proxy, transaction)) .await?; - item_state_proxy.commit(); + item_state_proxy.commit().await; Ok((transaction, item)) }).await } diff --git a/src/ship/location.rs b/src/ship/location.rs index 3e3c388..037df94 100644 --- a/src/ship/location.rs +++ b/src/ship/location.rs @@ -91,15 +91,22 @@ pub enum GetLeaderError { } #[derive(Error, Debug, PartialEq, Eq)] -#[error("clientlocation")] pub enum ClientLocationError { + #[error("create room error {0}")] CreateRoomError(#[from] CreateRoomError), + #[error("join room error {0}")] JoinRoomError(#[from] JoinRoomError), + #[error("join lobby error {0}")] JoinLobbyError(#[from] JoinLobbyError), + #[error("get area error {0}")] GetAreaError(#[from] GetAreaError), + #[error("client removal error {0}")] ClientRemovalError(#[from] ClientRemovalError), + #[error("get clients error {0}")] GetClientsError(#[from] GetClientsError), + #[error("get neighbor error {0}")] GetNeighborError(#[from] GetNeighborError), + #[error("get leader error {0}")] GetLeaderError(#[from] GetLeaderError) } diff --git a/src/ship/map/area.rs b/src/ship/map/area.rs index eb6bb68..4cb22ee 100644 --- a/src/ship/map/area.rs +++ b/src/ship/map/area.rs @@ -318,8 +318,10 @@ impl fmt::Display for MapArea { pub struct MapAreaLookup(HashMap); impl MapAreaLookup { - pub fn get_area_map(&self, map_area: u16) -> Result<&MapArea, MapAreaError> { - self.0.get(&map_area).ok_or(MapAreaError::UnknownMapArea(map_area)) + pub fn get_area_map(&self, map_area: u16) -> Result { + self.0.get(&map_area) + .map(|a| *a) + .ok_or(MapAreaError::UnknownMapArea(map_area)) } fn default_ep1_maps() -> MapAreaLookup { diff --git a/src/ship/map/maps.rs b/src/ship/map/maps.rs index 0743c01..6c971fc 100644 --- a/src/ship/map/maps.rs +++ b/src/ship/map/maps.rs @@ -345,7 +345,6 @@ impl Maps { pub fn roll_monster_appearance(&mut self, rare_monster_table: &RareMonsterAppearTable) { self.enemy_data = self.enemy_data .iter() - // .map(|&x| if x.is_some() && x.unwrap().has_rare_appearance() { .map(|&x| if let Some(monster) = x { if monster.has_rare_appearance() { diff --git a/src/ship/mod.rs b/src/ship/mod.rs index 7ad6a1b..3bc573b 100644 --- a/src/ship/mod.rs +++ b/src/ship/mod.rs @@ -2,6 +2,7 @@ pub mod ship; pub mod location; pub mod character; +pub mod client; pub mod room; pub mod items; pub mod item_stats; diff --git a/src/ship/packet/builder/lobby.rs b/src/ship/packet/builder/lobby.rs index a976f02..86da981 100644 --- a/src/ship/packet/builder/lobby.rs +++ b/src/ship/packet/builder/lobby.rs @@ -5,21 +5,34 @@ use crate::ship::location::{ClientLocation, LobbyId, ClientLocationError}; use crate::ship::packet::builder::{player_info}; use crate::ship::items::state::ItemState; +use futures::future::join_all; pub async fn join_lobby(id: ClientId, lobby: LobbyId, client_location: &ClientLocation, clients: &Clients, item_state: &ItemState) - -> Result { + -> Result { let lobby_clients = client_location.get_clients_in_lobby(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?; - let playerinfo = lobby_clients.iter() - .map(|area_client| { - let client = clients.get(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client)).unwrap(); - player_info(0x100, client, area_client, item_state) - }); - let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); + let playerinfo = join_all( + lobby_clients.into_iter() + .map(|area_client| { + let item_state = item_state.clone(); + async move { + clients.with(area_client.client, |client| Box::pin(async move { + let inventory = item_state.get_character_inventory(&client.character).await?; + Ok(player_info(0x100, client, &area_client, &inventory).await) + })).await? + }})) + .await + .into_iter() + .collect::, ShipError>>()?; + + //let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); + let client_block = clients.with(id, |client| Box::pin(async move { + client.block as u16 + })).await?; let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let leader = client_location.get_lobby_leader(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?; Ok(JoinLobby { @@ -27,10 +40,10 @@ pub async fn join_lobby(id: ClientId, leader: leader.local_client.id(), one: 1, lobby: lobby.id(), - block: client.block as u16, + block: client_block, event: 0, padding: 0, - playerinfo: playerinfo.collect(), + playerinfo: playerinfo, }) } @@ -40,20 +53,24 @@ pub async fn add_to_lobby(id: ClientId, clients: &Clients, item_state: &ItemState) -> Result { - let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let leader = client_location.get_lobby_leader(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?; - Ok(AddToLobby { - flag: 1, - client: area_client.local_client.id(), - leader: leader.local_client.id(), - one: 1, - lobby: lobby.id(), - block: client.block as u16, - event: 0, - padding: 0, - playerinfo: player_info(0x100, client, &area_client, item_state), - }) + clients.with(id, |client| { + let item_state = item_state.clone(); + Box::pin(async move { + let inventory = item_state.get_character_inventory(&client.character).await?; + Ok(AddToLobby { + flag: 1, + client: area_client.local_client.id(), + leader: leader.local_client.id(), + one: 1, + lobby: lobby.id(), + block: client.block as u16, + event: 0, + padding: 0, + playerinfo: player_info(0x100, client, &area_client, &inventory).await, + }) + })}).await? } pub async fn remove_from_lobby(id: ClientId, diff --git a/src/ship/packet/builder/mod.rs b/src/ship/packet/builder/mod.rs index 76bdf31..f74015e 100644 --- a/src/ship/packet/builder/mod.rs +++ b/src/ship/packet/builder/mod.rs @@ -10,7 +10,7 @@ use crate::common::leveltable::LEVEL_TABLE; use crate::ship::character::CharacterBytesBuilder; use crate::ship::ship::ClientState; use crate::ship::location::AreaClient; -use crate::ship::items::state::ItemState; +use crate::ship::items::inventory::InventoryState; pub fn player_header(tag: u32, client: &ClientState, area_client: &AreaClient) -> PlayerHeader { PlayerHeader { @@ -23,9 +23,8 @@ pub fn player_header(tag: u32, client: &ClientState, area_client: &AreaClient) - } } -pub fn player_info(tag: u32, client: &ClientState, area_client: &AreaClient, item_state: &ItemState) -> PlayerInfo { +pub async fn player_info(tag: u32, client: &ClientState, area_client: &AreaClient, inventory: &InventoryState) -> PlayerInfo { let (level, stats) = LEVEL_TABLE.get_stats_from_exp(client.character.char_class, client.character.exp); - let inventory = item_state.get_character_inventory(&client.character).unwrap(); let character = CharacterBytesBuilder::default() .character(&client.character) .stats(&stats) diff --git a/src/ship/packet/builder/room.rs b/src/ship/packet/builder/room.rs index 6b55f21..4ff4696 100644 --- a/src/ship/packet/builder/room.rs +++ b/src/ship/packet/builder/room.rs @@ -19,12 +19,14 @@ pub async fn join_room(id: ClientId, let players = futures::stream::iter(all_clients.iter()) .enumerate() .fold::, _, _>(Ok([PlayerHeader::default(); 4]), |acc, (i, c)| async move { - let header_client = clients.get(&c.client).ok_or(ShipError::ClientNotFound(id))?; + //let header_client = clients.get(&c.client).ok_or(ShipError::ClientNotFound(id))?; let header_area_client = client_location.get_local_client(id).await.map_err(|err| ShipError::ClientLocationError(err.into()))?; - acc.map(|mut a| { - a[i] = player_header(0x10000, header_client, &header_area_client); - a - }) + clients.with(c.client, |client| Box::pin(async move { + acc.map(|mut a| { + a[i] = player_header(0x10000, client, &header_area_client); + a + }) + })).await? }).await?; let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; @@ -50,7 +52,7 @@ pub async fn join_room(id: ClientId, } -pub fn add_to_room(_id: ClientId, +pub async fn add_to_room(_id: ClientId, client: &ClientState, area_client: &AreaClient, leader: &AreaClient, @@ -58,7 +60,7 @@ pub fn add_to_room(_id: ClientId, _room_id: RoomId, ) -> Result { - + let inventory = item_state.get_character_inventory(&client.character).await?; Ok(AddToRoom { flag: 1, client: area_client.local_client.id(), @@ -68,7 +70,7 @@ pub fn add_to_room(_id: ClientId, block: 0, event: 0, padding: 0, - playerinfo: player_info(0x10000, client, area_client, item_state), + playerinfo: player_info(0x10000, client, area_client, &inventory).await, }) } diff --git a/src/ship/packet/handler/auth.rs b/src/ship/packet/handler/auth.rs index e3ca60b..1ae4137 100644 --- a/src/ship/packet/handler/auth.rs +++ b/src/ship/packet/handler/auth.rs @@ -8,16 +8,19 @@ use crate::ship::items::state::ItemState; use crate::common::interserver::ShipMessage; #[allow(clippy::too_many_arguments)] -pub async fn validate_login(id: ClientId, - pkt: &Login, - mut entity_gateway: EG, - clients: &mut Clients, - item_state: &mut ItemState, - shipgate_sender: &Option>, - ship_name: &str, - num_blocks: usize) - -> Result, anyhow::Error> { - Ok(match get_login_status(&mut entity_gateway, pkt).await { +pub async fn validate_login(id: ClientId, + pkt: Login, + entity_gateway: &mut EG, + clients: &mut Clients, + item_state: &mut ItemState, + shipgate_sender: &Option>, + ship_name: &str, + num_blocks: usize) + -> Result, ShipError> +where + EG: EntityGateway, +{ + Ok(match get_login_status(entity_gateway, &pkt).await { Ok(user) => { let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::new()); response.guildcard = user.id.0 as u32; @@ -30,12 +33,12 @@ pub async fn validate_login(id: ClientId, .clone(); let settings = entity_gateway.get_user_settings_by_user(&user).await?; - item_state.load_character(&mut entity_gateway, &character).await?; + item_state.load_character(entity_gateway, &character).await?; if let Some(shipgate_sender) = shipgate_sender.as_ref() { - shipgate_sender(ShipMessage::AddUser(user.id)); + shipgate_sender.send(ShipMessage::AddUser(user.id)).await; } - clients.insert(id, ClientState::new(user, settings, character, pkt.session)); + clients.add(id, ClientState::new(user, settings, character, pkt.session)).await; vec![SendShipPacket::LoginResponse(response), SendShipPacket::ShipBlockList(ShipBlockList::new(ship_name, num_blocks))] }, Err(err) => { diff --git a/src/ship/packet/handler/communication.rs b/src/ship/packet/handler/communication.rs index 6a83033..eb16508 100644 --- a/src/ship/packet/handler/communication.rs +++ b/src/ship/packet/handler/communication.rs @@ -4,44 +4,58 @@ use crate::ship::ship::{SendShipPacket, ShipError, Clients}; use crate::ship::location::{ClientLocation}; use crate::entity::gateway::EntityGateway; -pub async fn player_chat(id: ClientId, - msg: &PlayerChat, - client_location: &ClientLocation, - clients: &Clients) -> Result + Send>, ShipError> { - let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - let cmsg = PlayerChat::new(client.user.id.0, msg.message.clone()); +use futures::future::join_all; - Ok(Box::new(client_location.get_all_clients_by_client(id).await.unwrap().into_iter() - .map(move |client| { - (client.client, SendShipPacket::PlayerChat(cmsg.clone())) - }))) +pub async fn player_chat(id: ClientId, + msg: PlayerChat, + client_location: &ClientLocation, + clients: &Clients) + -> Result, ShipError> { + let cmsg = clients.with(id, |client| Box::pin(async move { + PlayerChat::new(client.user.id.0, msg.message) + })).await?; + + Ok(client_location.get_all_clients_by_client(id).await.unwrap().into_iter() + .map(move |client| { + (client.client, SendShipPacket::PlayerChat(cmsg.clone()).clone()) + }) + .collect()) } pub async fn request_infoboard(id: ClientId, client_location: &ClientLocation, clients: &Clients) - -> Box + Send> { + -> Result, ShipError> { let area_clients = client_location.get_client_neighbors(id).await.unwrap(); - let r = area_clients.iter() - .filter_map(|c| { - clients.get(&c.client) - }) - .map(|client| { - InfoboardResponse { - name: libpso::utf8_to_utf16_array!(client.character.name, 16), - message: client.character.info_board.as_bytes(), - } - }).collect(); - Box::new(vec![(id, SendShipPacket::ViewInfoboardResponse(ViewInfoboardResponse {response: r}))].into_iter()) + let infoboards = join_all( + area_clients.iter() + .map(|client| async { + clients.with(client.client, |client| Box::pin(async move { + InfoboardResponse { + name: libpso::utf8_to_utf16_array!(client.character.name, 16), + message: client.character.info_board.as_bytes(), + } + })).await + })) + .await + .into_iter() + .collect::, ShipError>>()?; + Ok(vec![(id, SendShipPacket::ViewInfoboardResponse(ViewInfoboardResponse {response: infoboards}))]) } -pub async fn write_infoboard(id: ClientId, - new_infoboard: &WriteInfoboard, - clients: &mut Clients, - mut entity_gateway: EG) - -> Box + Send> { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); - client.character.info_board.update_infoboard(new_infoboard); - entity_gateway.save_character(&client.character).await.unwrap(); - Box::new(None.into_iter()) +pub async fn write_infoboard(id: ClientId, + new_infoboard: WriteInfoboard, + clients: &Clients, + entity_gateway: &mut EG) + -> Result, ShipError> +where + EG: EntityGateway + Clone + 'static, +{ + clients.with_mut(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + Box::pin(async move { + client.character.info_board.update_infoboard(&new_infoboard); + entity_gateway.save_character(&client.character).await + })}).await??; + Ok(Vec::new()) } diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index 4397ed5..29c64cf 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -5,9 +5,10 @@ use libpso::packet::ship::*; use libpso::packet::messages::*; use crate::common::leveltable::LEVEL_TABLE; use crate::common::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms, ItemShops}; +use crate::ship::ship::{SendShipPacket, ShipError, Clients, ItemShops}; use crate::ship::location::{ClientLocation, ClientLocationError}; use crate::ship::drops::ItemDrop; +use crate::ship::room::Rooms; use crate::ship::items::ClientItemId; use crate::entity::gateway::EntityGateway; use crate::entity::item; @@ -38,70 +39,73 @@ async fn send_to_client(id: ClientId, target: u8, msg: DirectMessage, client_location: &ClientLocation) - -> Box + Send> { - Box::new(client_location.get_all_clients_by_client(id).await.unwrap().into_iter() - .filter(move |client| client.local_client.id() == target) - .map(move |client| { - (client.client, SendShipPacket::DirectMessage(msg.clone())) - })) + -> Vec<(ClientId, SendShipPacket)> { + client_location.get_all_clients_by_client(id).await.unwrap().into_iter() + .filter(move |client| client.local_client.id() == target) + .map(move |client| { + (client.client, SendShipPacket::DirectMessage(msg.clone())) + }) + .collect() } pub async fn guildcard_send(id: ClientId, - guildcard_send: &GuildcardSend, + guildcard_send: GuildcardSend, target: u32, client_location: &ClientLocation, clients: &Clients) - -> Box + Send> { - let client = clients.get(&id).unwrap(); - let msg = DirectMessage{ - flag: target, - msg: GameMessage::GuildcardRecv(GuildcardRecv { - client: guildcard_send.client, - target: guildcard_send.target, - guildcard: client.user.id.0, - name: utf8_to_utf16_array!(client.character.name, 0x18), - team: [0; 0x10], // TODO: teams not yet implemented - desc: utf8_to_utf16_array!(client.character.guildcard.description, 0x58), - one: 1, - language: 0, // TODO: add language flag to character - section_id: client.character.section_id.into(), - class: client.character.char_class.into(), - }), - }; - send_to_client(id, target as u8, msg, client_location).await + -> Result, ShipError> { + let msg = clients.with(id, |client| Box::pin(async move { + DirectMessage{ + flag: target, + msg: GameMessage::GuildcardRecv(GuildcardRecv { + client: guildcard_send.client, + target: guildcard_send.target, + guildcard: client.user.id.0, + name: utf8_to_utf16_array!(client.character.name, 0x18), + team: [0; 0x10], // TODO: teams not yet implemented + desc: utf8_to_utf16_array!(client.character.guildcard.description, 0x58), + one: 1, + language: 0, // TODO: add language flag to character + section_id: client.character.section_id.into(), + class: client.character.char_class.into(), + }), + } + })).await?; + + Ok(send_to_client(id, target as u8, msg, client_location).await) } pub async fn request_item(id: ClientId, - request_item: &RequestItem, - mut entity_gateway: EG, + request_item: RequestItem, + entity_gateway: &mut EG, client_location: &ClientLocation, - clients: &mut Clients, - rooms: &mut Rooms, + clients: &Clients, + rooms: &Rooms, item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + -> Result, ShipError> where EG: EntityGateway { let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let room = rooms.get_mut(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? - .as_mut() - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; + let monster = rooms.with(room_id, |room| Box::pin(async move { + room.maps.enemy_by_id(request_item.enemy_id as usize) + })).await??; - let monster = room.maps.enemy_by_id(request_item.enemy_id as usize)?; if monster.dropped_item { return Err(ShipError::MonsterAlreadyDroppedItem(id, request_item.enemy_id).into()) } let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; - - let client_and_drop = clients_in_area.into_iter() - .filter_map(|area_client| { - room.drop_table.get_drop(&monster.map_area, &monster.monster).map(|item_drop_type| { - (area_client, item_drop_type) + let client_and_drop = rooms.with_mut(room_id, |room| Box::pin(async move { + clients_in_area.into_iter() + .filter_map(move |area_client| { + room.drop_table.get_drop(&monster.map_area, &monster.monster).map(|item_drop_type| { + (area_client, item_drop_type) + }) }) - }); - + .collect::>() + })).await?; + let mut item_drop_packets = Vec::new(); for (area_client, item_drop) in client_and_drop { let item_drop = ItemDrop { @@ -111,100 +115,108 @@ where z: request_item.z, item: item_drop, }; - let client = clients.get_mut(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client))?; - let floor_item = enemy_drops_item(item_state, &mut entity_gateway, client.character.id, item_drop).await?; + let character_id = clients.with(id, |client| Box::pin(async move { + client.character.id + })).await?; + + let floor_item = enemy_drops_item(item_state, entity_gateway, character_id, item_drop).await?; let item_drop_msg = builder::message::item_drop(request_item.client, request_item.target, &floor_item)?; item_drop_packets.push((area_client.client, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(item_drop_msg))))); } - Ok(Box::new(item_drop_packets.into_iter())) + Ok(item_drop_packets) } pub async fn pickup_item(id: ClientId, - pickup_item: &PickupItem, - mut entity_gateway: EG, - client_location: &ClientLocation, - clients: &mut Clients, - item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + pickup_item: PickupItem, + entity_gateway: &mut EG, + client_location: &ClientLocation, + clients: &Clients, + item_state: &mut ItemState) + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static, { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let (item, floor_type) = item_state.get_floor_item(&client.character.id, &ClientItemId(pickup_item.item_id))?; - let remove_item = builder::message::remove_item_from_floor(area_client, item)?; - let create_item = match &item.item { - FloorItemDetail::Individual(individual_floor_item) => Some(builder::message::create_individual_item(area_client, item.item_id, individual_floor_item)?), - FloorItemDetail::Stacked(stacked_floor_item) => Some(builder::message::create_stacked_item(area_client, item.item_id, &stacked_floor_item.tool, stacked_floor_item.count())?), - FloorItemDetail::Meseta(_) => None, - }; - - match pick_up_item(item_state, &mut entity_gateway, &client.character, &ClientItemId(pickup_item.item_id)).await { - Ok(trigger_create_item) => { - let remove_packets: Box + Send> = match floor_type { - FloorType::Local => { - Box::new(vec![(id, SendShipPacket::Message(Message::new(GameMessage::RemoveItemFromFloor(remove_item.clone()))))].into_iter()) - }, - FloorType::Shared => { - Box::new(clients_in_area.clone().into_iter() - .map(move |c| { - (c.client, SendShipPacket::Message(Message::new(GameMessage::RemoveItemFromFloor(remove_item.clone())))) - })) - }, + clients.with(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + let (item, floor_type) = item_state.get_floor_item(&client.character.id, &ClientItemId(pickup_item.item_id)).await?; + let remove_item = builder::message::remove_item_from_floor(area_client, &item)?; + let create_item = match &item.item { + FloorItemDetail::Individual(individual_floor_item) => Some(builder::message::create_individual_item(area_client, item.item_id, individual_floor_item)?), + FloorItemDetail::Stacked(stacked_floor_item) => Some(builder::message::create_stacked_item(area_client, item.item_id, &stacked_floor_item.tool, stacked_floor_item.count())?), + FloorItemDetail::Meseta(_) => None, }; - Ok(Box::new(remove_packets - .chain(clients_in_area.into_iter(). - filter_map(move |c| { - match trigger_create_item { - TriggerCreateItem::Yes => create_item.clone().map(|ci| (c.client, SendShipPacket::Message(Message::new(GameMessage::CreateItem(ci))))), - _ => None - } - } - )))) - }, - Err(err) => { - warn!("character {:?} could not pick up item: {:?}", client.character.id, err); - Ok(Box::new(None.into_iter())) - }, - } + match pick_up_item(&mut item_state, &mut entity_gateway, &client.character, &ClientItemId(pickup_item.item_id)).await { + Ok(trigger_create_item) => { + let remove_packets: Box + Send> = match floor_type { + FloorType::Local => { + Box::new(vec![(id, SendShipPacket::Message(Message::new(GameMessage::RemoveItemFromFloor(remove_item.clone()))))].into_iter()) + }, + FloorType::Shared => { + Box::new(clients_in_area.clone().into_iter() + .map(move |c| { + (c.client, SendShipPacket::Message(Message::new(GameMessage::RemoveItemFromFloor(remove_item.clone())))) + })) + }, + }; + + Ok(remove_packets + .chain(clients_in_area.into_iter() + .filter_map(move |c| { + match trigger_create_item { + TriggerCreateItem::Yes => create_item.clone().map(|ci| (c.client, SendShipPacket::Message(Message::new(GameMessage::CreateItem(ci))))), + _ => None + } + })) + .collect()) + }, + Err(err) => { + warn!("character {:?} could not pick up item: {:?}", client.character.id, err); + Ok(Vec::new()) + }, + } + })}).await? } pub async fn request_box_item(id: ClientId, - box_drop_request: &BoxDropRequest, - mut entity_gateway: EG, + box_drop_request: BoxDropRequest, + entity_gateway: &mut EG, client_location: &ClientLocation, - clients: &mut Clients, - rooms: &mut Rooms, + clients: &Clients, + rooms: &Rooms, item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static { let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let room = rooms.get_mut(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? - .as_mut() - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; + let box_object = rooms.with(room_id, |room| Box::pin(async move { + room.maps.object_by_id(box_drop_request.object_id as usize) + })).await??; - let box_object = room.maps.object_by_id(box_drop_request.object_id as usize)?; if box_object.dropped_item { return Err(ShipError::BoxAlreadyDroppedItem(id, box_drop_request.object_id).into()) } let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; - - let client_and_drop = clients_in_area.into_iter() - .filter_map(|area_client| { - room.drop_table.get_box_drop(&box_object.map, &box_object).map(|item_drop_type| { - (area_client, item_drop_type) + + let client_and_drop = rooms.with_mut(room_id, |room| Box::pin(async move { + clients_in_area.into_iter() + .filter_map(move |area_client| { + room.drop_table.get_box_drop(&box_object.map, &box_object).map(|item_drop_type| { + (area_client, item_drop_type) + }) }) - }); + .collect::>() + })).await?; let mut item_drop_packets = Vec::new(); for (area_client, item_drop) in client_and_drop { @@ -215,94 +227,145 @@ where z: box_drop_request.z, item: item_drop, }; - let client = clients.get_mut(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client))?; - let floor_item = enemy_drops_item(item_state, &mut entity_gateway, client.character.id, item_drop).await?; + //let client = clients.get_mut(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client))?; + let character_id = clients.with(area_client.client, |client| Box::pin(async move { + client.character.id + })).await?; + let floor_item = enemy_drops_item(item_state, entity_gateway, character_id, item_drop).await?; + //let floor_item = enemy_drops_item(item_state, &mut entity_gateway, client.character.id, item_drop).await?; let item_drop_msg = builder::message::item_drop(box_drop_request.client, box_drop_request.target, &floor_item)?; item_drop_packets.push((area_client.client, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(item_drop_msg))))) } - Ok(Box::new(item_drop_packets.into_iter())) + Ok(item_drop_packets) } -// item_manager is not mutable in this, but for reasons I don't quite understand it requires the unique access of it to compile here pub async fn send_bank_list(id: ClientId, clients: &Clients, item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + -> Result, ShipError> { - let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - let bank = item_state.get_character_bank(&client.character)?; - let bank_items_pkt = builder::message::bank_item_list(bank); - Ok(Box::new(vec![(id, SendShipPacket::BankItemList(bank_items_pkt))].into_iter())) + let bank = clients.with(id, |client| { + let item_state = item_state.clone(); + Box::pin(async move { + item_state.get_character_bank(&client.character).await + }) + }).await??; + let bank_items_pkt = builder::message::bank_item_list(&bank); + Ok(vec![(id, SendShipPacket::BankItemList(bank_items_pkt))]) } pub async fn bank_interaction(id: ClientId, - bank_interaction: &BankInteraction, - mut entity_gateway: EG, + bank_interaction: BankInteraction, + entity_gateway: &mut EG, client_location: &ClientLocation, - clients: &mut Clients, + clients: &Clients, item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static, { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let other_clients_in_area = client_location.get_all_clients_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let bank_action_pkts = match bank_interaction.action { - BANK_ACTION_DEPOSIT => { - if bank_interaction.item_id == 0xFFFFFFFF { - deposit_meseta(item_state, &mut entity_gateway, &client.character, bank_interaction.meseta_amount).await?; - Vec::new() - } - else { - deposit_item(item_state, &mut entity_gateway, &client.character, &ClientItemId(bank_interaction.item_id), bank_interaction.item_amount as u32).await?; - let player_no_longer_has_item = builder::message::player_no_longer_has_item(area_client, ClientItemId(bank_interaction.item_id), bank_interaction.item_amount as u32); - vec![SendShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(player_no_longer_has_item)))] - } - }, - BANK_ACTION_WITHDRAW => { - if bank_interaction.item_id == 0xFFFFFFFF { - withdraw_meseta(item_state, &mut entity_gateway, &client.character, bank_interaction.meseta_amount).await?; - Vec::new() - } - else { - let item_added_to_inventory = withdraw_item(item_state, &mut entity_gateway, &client.character, &ClientItemId(bank_interaction.item_id), bank_interaction.item_amount as u32).await?; - let item_created = builder::message::create_withdrawn_inventory_item2(area_client, &item_added_to_inventory)?; - vec![SendShipPacket::Message(Message::new(GameMessage::CreateItem(item_created)))] - } - }, - _ => { // TODO: error? - Vec::new() - } - }; - - Ok(Box::new(other_clients_in_area.into_iter() - .flat_map(move |c| { - bank_action_pkts.clone().into_iter() - .map(move |pkt| { - (c.client, pkt) - }) - }) - )) + + let bank_action_pkts = clients.with(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + Ok::<_, ShipError>(match bank_interaction.action { + BANK_ACTION_DEPOSIT => { + if bank_interaction.item_id == 0xFFFFFFFF { + deposit_meseta(&mut item_state, &mut entity_gateway, &client.character, bank_interaction.meseta_amount).await?; + Vec::new() + } + else { + deposit_item(&mut item_state, &mut entity_gateway, &client.character, &ClientItemId(bank_interaction.item_id), bank_interaction.item_amount as u32).await?; + let player_no_longer_has_item = builder::message::player_no_longer_has_item(area_client, ClientItemId(bank_interaction.item_id), bank_interaction.item_amount as u32); + vec![SendShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(player_no_longer_has_item)))] + } + }, + BANK_ACTION_WITHDRAW => { + if bank_interaction.item_id == 0xFFFFFFFF { + withdraw_meseta(&mut item_state, &mut entity_gateway, &client.character, bank_interaction.meseta_amount).await?; + Vec::new() + } + else { + let item_added_to_inventory = withdraw_item(&mut item_state, &mut entity_gateway, &client.character, &ClientItemId(bank_interaction.item_id), bank_interaction.item_amount as u32).await?; + let item_created = builder::message::create_withdrawn_inventory_item2(area_client, &item_added_to_inventory)?; + vec![SendShipPacket::Message(Message::new(GameMessage::CreateItem(item_created)))] + } + }, + _ => { // TODO: error? + Vec::new() + } + }) + }) + }).await??; + + Ok(other_clients_in_area.into_iter() + .flat_map(move |c| { + bank_action_pkts.clone().into_iter() + .map(move |pkt| { + (c.client, pkt) + }) + }) + .collect() + ) } pub async fn shop_request(id: ClientId, - shop_request: &ShopRequest, + shop_request: ShopRequest, client_location: &ClientLocation, - clients: &mut Clients, + clients: &Clients, rooms: &Rooms, - shops: &mut ItemShops) - -> Result + Send>, anyhow::Error> + shops: &ItemShops) + -> Result, ShipError> { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; + //let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + /* let room = rooms.get(room_id.0) .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? .as_ref() .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; - let level = LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp) as usize; + */ + let difficulty = rooms.with(room_id, |room| Box::pin(async move { + room.mode.difficulty() + })).await?; + let shop_list = clients.with_mut(id, |client| { + let mut shops = shops.clone(); + Box::pin(async move { + let level = LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp) as usize; + match shop_request.shop_type { + SHOP_OPTION_WEAPON => { + client.weapon_shop = shops.weapon_shop.get_mut(&(difficulty, client.character.section_id)) + .ok_or(ShipError::ShopError)? + .lock() + .await + .generate_weapon_list(level); + Ok(builder::message::shop_list(shop_request.shop_type, &client.weapon_shop)) + }, + SHOP_OPTION_TOOL => { + client.tool_shop = shops.tool_shop + .lock() + .await + .generate_tool_list(level); + Ok(builder::message::shop_list(shop_request.shop_type, &client.tool_shop)) + }, + SHOP_OPTION_ARMOR => { + client.armor_shop = shops.armor_shop + .lock() + .await + .generate_armor_list(level); + Ok(builder::message::shop_list(shop_request.shop_type, &client.armor_shop)) + }, + _ => { + Err(ShipError::ShopError) + } + } + })}).await??; + /* let shop_list = match shop_request.shop_type { SHOP_OPTION_WEAPON => { client.weapon_shop = shops.weapon_shop.get_mut(&(room.mode.difficulty(), client.character.section_id)) @@ -322,64 +385,69 @@ pub async fn shop_request(id: ClientId, return Err(ShipError::ShopError.into()) } }; + */ - Ok(Box::new(vec![(id, SendShipPacket::Message(Message::new(GameMessage::ShopList(shop_list))))].into_iter())) + Ok(vec![(id, SendShipPacket::Message(Message::new(GameMessage::ShopList(shop_list))))]) } pub async fn buy_item(id: ClientId, - buy_item: &BuyItem, - mut entity_gateway: EG, + buy_item: BuyItem, + entity_gateway: &mut EG, client_location: &ClientLocation, - clients: &mut Clients, + clients: &Clients, item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static, { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let (item, remove): (&(dyn ShopItem + Send + Sync), bool) = match buy_item.shop_type { - SHOP_OPTION_WEAPON => { - (client.weapon_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)?, false) - }, - SHOP_OPTION_TOOL => { - let item = client.tool_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)?; - let remove = matches!(item, ToolShopItem::Tech(_)); - (item, remove) - }, - SHOP_OPTION_ARMOR => { - let item = client.armor_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)?; - let remove = matches!(item, ArmorShopItem::Unit(_)); - (item, remove) - }, - _ => { - return Err(ShipError::ShopError.into()) - } - }; + let create = clients.with_mut(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + let (item, remove): (&(dyn ShopItem + Send + Sync), bool) = match buy_item.shop_type { + SHOP_OPTION_WEAPON => { + (client.weapon_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)?, false) + }, + SHOP_OPTION_TOOL => { + let item = client.tool_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)?; + let remove = matches!(item, ToolShopItem::Tech(_)); + (item, remove) + }, + SHOP_OPTION_ARMOR => { + let item = client.armor_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)?; + let remove = matches!(item, ArmorShopItem::Unit(_)); + (item, remove) + }, + _ => { + return Err(ShipError::ShopError.into()) + } + }; - let inventory_item = buy_shop_item(item_state, &mut entity_gateway, &client.character, item, ClientItemId(buy_item.item_id), buy_item.amount as u32).await?; - let create = builder::message::create_withdrawn_inventory_item(area_client, &inventory_item)?; + let inventory_item = buy_shop_item(&mut item_state, &mut entity_gateway, &client.character, item, ClientItemId(buy_item.item_id), buy_item.amount as u32).await?; - if remove { - match buy_item.shop_type { - SHOP_OPTION_TOOL => { - client.tool_shop.remove(buy_item.shop_index as usize); - }, - SHOP_OPTION_ARMOR => { - client.armor_shop.remove(buy_item.shop_index as usize); - }, - _ => {} - } - } + if remove { + match buy_item.shop_type { + SHOP_OPTION_TOOL => { + client.tool_shop.remove(buy_item.shop_index as usize); + }, + SHOP_OPTION_ARMOR => { + client.armor_shop.remove(buy_item.shop_index as usize); + }, + _ => {} + } + } + builder::message::create_withdrawn_inventory_item(area_client, &inventory_item) + })}).await??; let other_clients_in_area = client_location.get_client_neighbors(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - Ok(Box::new(other_clients_in_area.into_iter() - .map(move |c| { - (c.client, SendShipPacket::Message(Message::new(GameMessage::CreateItem(create.clone())))) - }))) - + Ok(other_clients_in_area.into_iter() + .map(move |c| { + (c.client, SendShipPacket::Message(Message::new(GameMessage::CreateItem(create.clone())))) + }) + .collect()) } @@ -393,15 +461,15 @@ const TEK_PERCENT_MODIFIER: [item::weapon::TekPercentModifier; 5] = [item::weapo item::weapon::TekPercentModifier::MinusMinus]; pub async fn request_tek_item(id: ClientId, - tek_request: &TekRequest, - mut entity_gateway: EG, - clients: &mut Clients, + tek_request: TekRequest, + entity_gateway: &mut EG, + clients: &Clients, item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static, { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; + //let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; // TODO: secids have different mod rates let (grind_mod, special_mod, percent_mod) = { @@ -413,63 +481,73 @@ where (grind_mod, special_mod, percent_mod) }; - client.tek = Some((ClientItemId(tek_request.item_id), special_mod, percent_mod, grind_mod)); + let preview_pkt = clients.with_mut(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + client.tek = Some((ClientItemId(tek_request.item_id), special_mod, percent_mod, grind_mod)); - let inventory = item_state.get_character_inventory(&client.character)?; - let item = inventory.get_by_client_id(&ClientItemId(tek_request.item_id)) - .ok_or(ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))?; - let mut weapon = *item.item.as_individual() - .ok_or(ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))? - .as_weapon() - .ok_or(ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))?; + let inventory = item_state.get_character_inventory(&client.character).await?; + let item = inventory.get_by_client_id(&ClientItemId(tek_request.item_id)) + .ok_or(ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))?; + let mut weapon = *item.item.as_individual() + .ok_or(ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))? + .as_weapon() + .ok_or(ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))?; - weapon.apply_modifier(&item::weapon::WeaponModifier::Tekked { - special: special_mod, - percent: percent_mod, - grind: grind_mod, - }); + weapon.apply_modifier(&item::weapon::WeaponModifier::Tekked { + special: special_mod, + percent: percent_mod, + grind: grind_mod, + }); - take_meseta(item_state, &mut entity_gateway, &client.character.id, item::Meseta(100)).await?; + take_meseta(&mut item_state, &mut entity_gateway, &client.character.id, item::Meseta(100)).await?; + builder::message::tek_preview(ClientItemId(tek_request.item_id), &weapon) + })}).await??; - let preview_pkt = builder::message::tek_preview(ClientItemId(tek_request.item_id), &weapon)?; - Ok(Box::new(vec![(id, SendShipPacket::Message(Message::new(GameMessage::TekPreview(preview_pkt))))].into_iter())) + Ok(vec![(id, SendShipPacket::Message(Message::new(GameMessage::TekPreview(preview_pkt))))]) } pub async fn accept_tek_item(id: ClientId, - tek_accept: &TekAccept, - mut entity_gateway: EG, + tek_accept: TekAccept, + entity_gateway: &mut EG, client_location: &ClientLocation, - clients: &mut Clients, + clients: &Clients, item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static, { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let neighbors = client_location.get_client_neighbors(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - if let Some((item_id, special_mod, percent_mod, grind_mod)) = client.tek { - if item_id.0 != tek_accept.item_id { - return Err(MessageError::MismatchedTekIds(item_id, ClientItemId(tek_accept.item_id)).into()); + clients.with(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + if let Some((item_id, special_mod, percent_mod, grind_mod)) = client.tek { + if item_id.0 != tek_accept.item_id { + return Err(MessageError::MismatchedTekIds(item_id, ClientItemId(tek_accept.item_id)).into()); + } + + let modifier = item::weapon::WeaponModifier::Tekked { + special: special_mod, + percent: percent_mod, + grind: grind_mod, + }; + let weapon = apply_modifier(&mut item_state, &mut entity_gateway, &client.character, item_id, item::ItemModifier::WeaponModifier(modifier)).await?; + + let create_item_pkt = builder::message::create_individual_item(area_client, item_id, &weapon)?; + + Ok(neighbors.into_iter() + .map(move |c| { + (c.client, SendShipPacket::Message(Message::new(GameMessage::CreateItem(create_item_pkt.clone())))) + }) + .collect()) } - - let modifier = item::weapon::WeaponModifier::Tekked { - special: special_mod, - percent: percent_mod, - grind: grind_mod, - }; - let weapon = apply_modifier(item_state, &mut entity_gateway, &client.character, item_id, item::ItemModifier::WeaponModifier(modifier)).await?; - - let create_item_pkt = builder::message::create_individual_item(area_client, item_id, &weapon)?; - - let neighbors = client_location.get_client_neighbors(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - Ok(Box::new(neighbors.into_iter() - .map(move |c| { - (c.client, SendShipPacket::Message(Message::new(GameMessage::CreateItem(create_item_pkt.clone())))) - }))) - } - else { - Err(MessageError::InvalidTek(ClientItemId(tek_accept.item_id)).into()) - } + else { + Err(MessageError::InvalidTek(ClientItemId(tek_accept.item_id)).into()) + } + })}).await? } diff --git a/src/ship/packet/handler/lobby.rs b/src/ship/packet/handler/lobby.rs index 3d133ad..692740e 100644 --- a/src/ship/packet/handler/lobby.rs +++ b/src/ship/packet/handler/lobby.rs @@ -1,57 +1,62 @@ use libpso::packet::ship::*; use crate::common::serverstate::ClientId; use crate::common::leveltable::LEVEL_TABLE; -use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms}; +use crate::ship::ship::{SendShipPacket, ShipError, Clients}; +use crate::ship::room::Rooms; use crate::ship::character::{FullCharacterBytesBuilder}; use crate::ship::location::{ClientLocation, LobbyId, RoomLobby, ClientLocationError, RoomId}; use crate::ship::packet; use crate::ship::items::state::ItemState; use crate::entity::gateway::EntityGateway; use crate::ship::map::MapArea; +use futures::future::join_all; // this function needs a better home -pub fn block_selected(id: ClientId, - pkt: &MenuSelect, - clients: &mut Clients, - item_state: &ItemState) - -> Result, anyhow::Error> { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - client.block = pkt.item as usize - 1; +pub async fn block_selected(id: ClientId, + pkt: MenuSelect, + clients: &Clients, + item_state: &ItemState) + -> Result, ShipError> { + clients.with_mut(id, |client| { + let item_state = item_state.clone(); + Box::pin(async move { + client.block = pkt.item as usize - 1; - let (level, stats) = LEVEL_TABLE.get_stats_from_exp(client.character.char_class, client.character.exp); + let (level, stats) = LEVEL_TABLE.get_stats_from_exp(client.character.char_class, client.character.exp); - let inventory = item_state.get_character_inventory(&client.character).unwrap(); - let bank = item_state.get_character_bank(&client.character).unwrap(); + let inventory = item_state.get_character_inventory(&client.character).await?; + let bank = item_state.get_character_bank(&client.character).await?; - let fc = FullCharacterBytesBuilder::default() - .character(&client.character) - .stats(&stats) - .level(level) - .meseta(inventory.meseta) - .inventory(inventory) - .bank(bank) - .keyboard_config(&client.character.keyboard_config.as_bytes()) - .gamepad_config(&client.character.gamepad_config.as_bytes()) - .symbol_chat(&client.settings.settings.symbol_chats) - .tech_menu(&client.character.tech_menu.as_bytes()) - .option_flags(client.character.option_flags) - .build(); + let fc = FullCharacterBytesBuilder::default() + .character(&client.character) + .stats(&stats) + .level(level) + .meseta(inventory.meseta) + .inventory(&inventory) + .bank(&bank) + .keyboard_config(&client.character.keyboard_config.as_bytes()) + .gamepad_config(&client.character.gamepad_config.as_bytes()) + .symbol_chat(&client.settings.settings.symbol_chats) + .tech_menu(&client.character.tech_menu.as_bytes()) + .option_flags(client.character.option_flags) + .build(); - Ok(vec![ - (id, SendShipPacket::FullCharacter(Box::new(FullCharacter { - character: fc, - }))), - (id, SendShipPacket::CharDataRequest(CharDataRequest {})), - (id, SendShipPacket::LobbyList(LobbyList::new())), - ]) + Ok(vec![ + (id, SendShipPacket::FullCharacter(Box::new(FullCharacter { + character: fc, + }))), + (id, SendShipPacket::CharDataRequest(CharDataRequest {})), + (id, SendShipPacket::LobbyList(LobbyList::new())), + ]) + })}).await? } pub async fn send_player_to_lobby(id: ClientId, - _pkt: &CharData, + _pkt: CharData, client_location: &mut ClientLocation, clients: &Clients, item_state: &ItemState) - -> Result, anyhow::Error> { + -> Result, ShipError> { let lobby = client_location.add_client_to_next_available_lobby(id, LobbyId(0)).await.map_err(|_| ShipError::TooManyClients)?; let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_state).await?; let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state).await?; @@ -63,15 +68,17 @@ pub async fn send_player_to_lobby(id: ClientId, } #[allow(clippy::too_many_arguments)] -pub async fn change_lobby(id: ClientId, - requested_lobby: u32, - client_location: &mut ClientLocation, - clients: &Clients, - item_state: &mut ItemState, - ship_rooms: &mut Rooms, - mut entity_gateway: EG) - -> Result, anyhow::Error> { - let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; +pub async fn change_lobby(id: ClientId, + requested_lobby: u32, + client_location: &mut ClientLocation, + clients: &Clients, + item_state: &mut ItemState, + rooms: &Rooms, + entity_gateway: &mut EG) + -> Result, ShipError> +where + EG: EntityGateway + Clone + 'static, +{ let prev_area = client_location.get_area(id).await.map_err(|err| -> ClientLocationError {err.into()})?; match prev_area { RoomLobby::Lobby(old_lobby) => { @@ -81,9 +88,13 @@ pub async fn change_lobby(id: ClientId, }, RoomLobby::Room(old_room) => { if client_location.get_client_neighbors(id).await?.is_empty() { - ship_rooms[old_room.0] = None; + rooms.remove(old_room).await; } - item_state.remove_character_from_room(&client.character); + clients.with(id, |client| { + let mut item_state = item_state.clone(); + Box::pin(async move { + item_state.remove_character_from_room(&client.character).await; + })}).await?; }, } let leave_lobby = packet::builder::lobby::remove_from_lobby(id, client_location).await?; @@ -100,10 +111,15 @@ pub async fn change_lobby(id: ClientId, } } } - item_state.load_character(&mut entity_gateway, &client.character).await?; + clients.with(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + item_state.load_character(&mut entity_gateway, &client.character).await + })}).await??; let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_state).await?; let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state).await?; - let neighbors = client_location.get_client_neighbors(id).await.unwrap(); + let neighbors = client_location.get_client_neighbors(id).await?; Ok(vec![(id, SendShipPacket::JoinLobby(join_lobby))] .into_iter() .chain(neighbors.into_iter() @@ -115,24 +131,25 @@ pub async fn change_lobby(id: ClientId, pub async fn remove_from_lobby(id: ClientId, client_location: &mut ClientLocation) - -> Result, anyhow::Error> { + -> Result, ShipError> { let area_client = client_location.get_local_client(id).await?; let neighbors = client_location.get_client_neighbors(id).await?; - let leader = client_location.get_leader_by_client(id).await?; + let leader = client_location.get_leader_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let leave_lobby_pkt = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())); - client_location.remove_client_from_area(id).await?; + client_location.remove_client_from_area(id).await.map_err(|err| -> ClientLocationError { err.into() })?; Ok(neighbors.into_iter().map(|n| { (n.client, leave_lobby_pkt.clone()) }).collect()) } pub async fn get_room_tab_info(id: ClientId, - pkt: &MenuDetail, + pkt: MenuDetail, client_location: &mut ClientLocation, clients: &Clients, rooms: &mut Rooms) - -> Result, anyhow::Error> { + -> Result, ShipError> { + /* let room_id = RoomId(pkt.item as usize); if let Some(_room) = rooms.get(pkt.item as usize).ok_or(ShipError::InvalidRoom(pkt.item))? { let mut room_info = String::new(); @@ -151,4 +168,34 @@ pub async fn get_room_tab_info(id: ClientId, } else { Ok(vec![(id, SendShipPacket::SmallLeftDialog(SmallLeftDialog::new("Game is no longer active".into())))]) } + */ + dbg!("a"); + let room_id = RoomId(pkt.item as usize); + dbg!("b"); + let clients_in_room = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; + dbg!("c"); + let room_info = if clients_in_room.len() == 0 { + dbg!("d"); + String::from("Game is no longer active") + } + else { + dbg!("d2"); + join_all(clients_in_room.iter() + .map(|clientl| async move { + dbg!("e"); + clients.with(clientl.client, |client| Box::pin(async move { + dbg!("f"); + format!("{} Lv{} {}\n{} {}", + client.character.name, + LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp), + client.user.guildcard, + client.character.char_class, + client.area.unwrap_or(MapArea::Pioneer2Ep1)) + })).await + })).await + .into_iter() + .collect::, ShipError>>()? + .join("\n") + }; + Ok(vec![(id, SendShipPacket::SmallLeftDialog(SmallLeftDialog::new(room_info)))]) } diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs index c738078..823b83b 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -4,179 +4,218 @@ use crate::entity::gateway::EntityGateway; use crate::entity::item::Meseta; use crate::common::serverstate::ClientId; use crate::common::leveltable::LEVEL_TABLE; -use crate::ship::ship::{SendShipPacket, ShipError, Rooms, Clients, ItemDropLocation}; +use crate::ship::ship::{SendShipPacket, ShipError, Clients, ItemDropLocation}; +use crate::ship::room::Rooms; use crate::ship::location::{ClientLocation, ClientLocationError}; use crate::ship::items::ClientItemId; use crate::ship::packet::builder; use crate::ship::items::state::ItemState; use crate::ship::items::tasks::{drop_item, drop_partial_item, drop_meseta, equip_item, unequip_item, sort_inventory, use_item, feed_mag, sell_item, take_meseta}; -pub async fn request_exp(id: ClientId, - request_exp: &RequestExp, - mut entity_gateway: EG, - client_location: &ClientLocation, - clients: &mut Clients, - rooms: &mut Rooms) - -> Result + Send>, anyhow::Error> { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; +pub async fn request_exp(id: ClientId, + request_exp: RequestExp, + entity_gateway: &mut EG, + client_location: &ClientLocation, + clients: &Clients, + rooms: &Rooms) + -> Result, ShipError> +where + EG: EntityGateway + Clone + 'static, +{ let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let room = rooms.get_mut(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? - .as_mut() - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; - let monster = room.maps.enemy_by_id(request_exp.enemy_id as usize)?; - let monster_stats = room.monster_stats.get(&monster.monster).ok_or(ShipError::UnknownMonster(monster.monster))?; + let enemy_id = request_exp.enemy_id as usize; + let enemy_exp = rooms.with(room_id, |room| Box::pin(async move { + let monster = room.maps.enemy_by_id(enemy_id)?; + let monster_stats = room.monster_stats.get(&monster.monster).ok_or(ShipError::UnknownMonster(monster.monster))?; + Ok::<_, ShipError>(monster_stats.exp) + })).await??; let exp_gain = if request_exp.last_hitter == 1 { - monster_stats.exp + enemy_exp } else { - ((monster_stats.exp as f32) * 0.8) as u32 + ((enemy_exp as f32) * 0.8) as u32 }; let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; let gain_exp_pkt = builder::message::character_gained_exp(area_client, exp_gain); - let mut exp_pkts: Box + Send> = Box::new(clients_in_area.clone().into_iter() + let mut exp_pkts: Vec<_> = clients_in_area.clone().into_iter() .map(move |c| { (c.client, SendShipPacket::Message(Message::new(GameMessage::GiveCharacterExp(gain_exp_pkt.clone())))) - })); + }) + .collect(); - let before_level = LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp); - let after_level = LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp + exp_gain); + let (char_class, exp) = clients.with(id, |client| Box::pin(async move { + (client.character.char_class, client.character.exp) + })).await?; + + let before_level = LEVEL_TABLE.get_level_from_exp(char_class, exp); + let after_level = LEVEL_TABLE.get_level_from_exp(char_class, exp + exp_gain); let level_up = before_level != after_level; if level_up { - let (_, before_stats) = LEVEL_TABLE.get_stats_from_exp(client.character.char_class, client.character.exp); - let (after_level, after_stats) = LEVEL_TABLE.get_stats_from_exp(client.character.char_class, client.character.exp + exp_gain); + let (_, before_stats) = LEVEL_TABLE.get_stats_from_exp(char_class, exp); + let (after_level, after_stats) = LEVEL_TABLE.get_stats_from_exp(char_class, exp + exp_gain); let level_up_pkt = builder::message::character_leveled_up(area_client, after_level, before_stats, after_stats); - exp_pkts = Box::new(exp_pkts.chain(clients_in_area.into_iter() - .map(move |c| { - (c.client, SendShipPacket::Message(Message::new(GameMessage::PlayerLevelUp(level_up_pkt.clone())))) - }))) + exp_pkts.extend(clients_in_area.into_iter() + .map(move |c| { + (c.client, SendShipPacket::Message(Message::new(GameMessage::PlayerLevelUp(level_up_pkt.clone())))) + })); } - client.character.exp += exp_gain; - entity_gateway.save_character(&client.character).await?; + clients.with_mut(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + Box::pin(async move { + client.character.exp += exp_gain; + entity_gateway.save_character(&client.character).await + })}).await??; Ok(exp_pkts) } pub async fn player_drop_item(id: ClientId, - player_drop_item: &PlayerDropItem, - mut entity_gateway: EG, + player_drop_item: PlayerDropItem, + entity_gateway: &mut EG, client_location: &ClientLocation, - clients: &mut Clients, - rooms: &mut Rooms, + clients: &Clients, + rooms: &Rooms, item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static, { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let room = rooms.get_mut(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? - .as_mut() - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; - let area = room.map_areas.get_area_map(player_drop_item.map_area)?; - drop_item(item_state, &mut entity_gateway, &client.character, &ClientItemId(player_drop_item.item_id), *area, (player_drop_item.x, player_drop_item.y, player_drop_item.z)).await?; + let map_area = rooms.with(room_id, |room| Box::pin(async move { + room.map_areas.get_area_map(player_drop_item.map_area) + })).await??; + + clients.with(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + drop_item(&mut item_state, &mut entity_gateway, &client.character, &ClientItemId(player_drop_item.item_id), map_area, (player_drop_item.x, player_drop_item.y, player_drop_item.z)).await + })}).await??; let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; let pdi = player_drop_item.clone(); - Ok(Box::new(clients_in_area.into_iter() - .map(move |c| { - (c.client, SendShipPacket::Message(Message::new(GameMessage::PlayerDropItem(pdi.clone())))) - }))) + Ok(clients_in_area.into_iter() + .map(move |c| { + (c.client, SendShipPacket::Message(Message::new(GameMessage::PlayerDropItem(pdi.clone())))) + }) + .collect()) } pub async fn drop_coordinates(id: ClientId, - drop_coordinates: &DropCoordinates, + drop_coordinates: DropCoordinates, client_location: &ClientLocation, - clients: &mut Clients, + clients: &Clients, rooms: &Rooms) - -> Result + Send>, anyhow::Error> + -> Result, ShipError> { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let room = rooms.get(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? - .as_ref() - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; + let map_area = rooms.with(room_id, |room| Box::pin(async move { + room.map_areas.get_area_map(drop_coordinates.map_area) + })).await??; - client.item_drop_location = Some(ItemDropLocation { - map_area: *room.map_areas.get_area_map(drop_coordinates.map_area)?, - x: drop_coordinates.x, - z: drop_coordinates.z, - item_id: ClientItemId(drop_coordinates.item_id), - }); + clients.with_mut(id, |client| Box::pin(async move { + client.item_drop_location = Some(ItemDropLocation { + map_area, + x: drop_coordinates.x, + z: drop_coordinates.z, + item_id: ClientItemId(drop_coordinates.item_id), + }); + })).await?; - Ok(Box::new(None.into_iter())) // TODO: do we need to send a packet here? + Ok(Vec::new()) // TODO: do we need to send a packet here? } pub async fn no_longer_has_item(id: ClientId, - no_longer_has_item: &PlayerNoLongerHasItem, - mut entity_gateway: EG, + no_longer_has_item: PlayerNoLongerHasItem, + entity_gateway: &mut EG, client_location: &ClientLocation, - clients: &mut Clients, + clients: &Clients, item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static, { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; + //let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - if let Some(drop_location) = client.item_drop_location { + + let (drop_location, tek) = clients.with(id, |client| Box::pin(async move { + (client.item_drop_location, client.tek) + })).await?; + if let Some(drop_location) = drop_location { if drop_location.item_id.0 != no_longer_has_item.item_id { return Err(ShipError::DropInvalidItemId(no_longer_has_item.item_id).into()); } if no_longer_has_item.item_id == 0xFFFFFFFF { - let dropped_meseta = drop_meseta(item_state, &mut entity_gateway, &client.character, drop_location.map_area, (drop_location.x, drop_location.z), no_longer_has_item.amount).await?; + let dropped_meseta = clients.with_mut(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + client.item_drop_location = None; + drop_meseta(&mut item_state, &mut entity_gateway, &client.character, drop_location.map_area, (drop_location.x, drop_location.z), no_longer_has_item.amount).await + })}).await??; let dropped_meseta_pkt = builder::message::drop_split_meseta_stack(area_client, &dropped_meseta)?; let no_longer_has_meseta_pkt = builder::message::player_no_longer_has_meseta(area_client, no_longer_has_item.amount as u32); - client.item_drop_location = None; let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; - Ok(Box::new(clients_in_area.into_iter() - .flat_map(move |c| { - std::iter::once((c.client, SendShipPacket::Message(Message::new(GameMessage::DropSplitStack(dropped_meseta_pkt.clone()))))) - .chain( - if c.client != id { - Box::new(std::iter::once( - (c.client, SendShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(no_longer_has_meseta_pkt.clone())))) - )) as Box + Send> - } - else { - Box::new(std::iter::empty()) as Box + Send> - } - ) - }) - )) + Ok(clients_in_area.into_iter() + .flat_map(move |c| { + std::iter::once((c.client, SendShipPacket::Message(Message::new(GameMessage::DropSplitStack(dropped_meseta_pkt.clone()))))) + .chain( + if c.client != id { + Box::new(std::iter::once( + (c.client, SendShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(no_longer_has_meseta_pkt.clone())))) + )) as Box + Send> + } + else { + Box::new(std::iter::empty()) as Box + Send> + } + ) + }) + .collect() + ) } else { - let dropped_item = drop_partial_item(item_state, &mut entity_gateway, &client.character, &drop_location.item_id, drop_location.map_area, (drop_location.x, drop_location.z), no_longer_has_item.amount).await?; - + let dropped_item = clients.with_mut(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + client.item_drop_location = None; + drop_partial_item(&mut item_state, + &mut entity_gateway, + &client.character, + &drop_location.item_id, + drop_location.map_area, + (drop_location.x, drop_location.z), + no_longer_has_item.amount) + .await + })}).await??; let dropped_item_pkt = builder::message::drop_split_stack(area_client, &dropped_item)?; - client.item_drop_location = None; let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; - Ok(Box::new(clients_in_area.into_iter() - .map(move |c| { - (c.client, SendShipPacket::Message(Message::new(GameMessage::DropSplitStack(dropped_item_pkt.clone())))) - }))) + Ok(clients_in_area.into_iter() + .map(move |c| { + (c.client, SendShipPacket::Message(Message::new(GameMessage::DropSplitStack(dropped_item_pkt.clone())))) + }) + .collect()) } } - else if let Some(_tek) = client.tek { + else if let Some(_tek) = tek { let neighbors = client_location.get_client_neighbors(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let no_longer_has_item = no_longer_has_item.clone(); - Ok(Box::new(neighbors.into_iter() - .map(move |c| { - (c.client, SendShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(no_longer_has_item.clone())))) - }))) + Ok(neighbors.into_iter() + .map(move |c| { + (c.client, SendShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(no_longer_has_item.clone())))) + }) + .collect()) } else { Err(ShipError::InvalidItem(ClientItemId(no_longer_has_item.item_id)).into()) @@ -184,201 +223,233 @@ where } pub async fn update_player_position(id: ClientId, - message: &Message, - clients: &mut Clients, + message: Message, + clients: &Clients, client_location: &ClientLocation, rooms: &Rooms) - -> Result + Send>, anyhow::Error> { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; + -> Result, ShipError> { if let Ok(room_id) = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() }) { - let room = rooms.get(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? - .as_ref() - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; - - match &message.msg { - GameMessage::PlayerChangedMap(p) => { - client.x = p.x; - client.y = p.y; - client.z = p.z; - }, - GameMessage::PlayerChangedMap2(p) => { - client.area = room.map_areas.get_area_map(p.map_area).ok().cloned(); - }, - GameMessage::TellOtherPlayerMyLocation(p) => { - client.x = p.x; - client.y = p.y; - client.z = p.z; - client.area = room.map_areas.get_area_map(p.map_area).ok().cloned(); - }, - GameMessage::PlayerWarpingToFloor(p) => { - client.area = room.map_areas.get_area_map(p.area as u16).ok().cloned(); - }, - GameMessage::PlayerTeleported(p) => { - client.x = p.x; - client.y = p.y; - client.z = p.z; - }, - GameMessage::PlayerStopped(p) => { - client.x = p.x; - client.y = p.y; - client.z = p.z; - }, - GameMessage::PlayerLoadedIn(p) => { - client.x = p.x; - client.y = p.y; - client.z = p.z; - }, - GameMessage::PlayerWalking(p) => { - client.x = p.x; - client.z = p.z; - }, - GameMessage::PlayerRunning(p) => { - client.x = p.x; - client.z = p.z; - }, - GameMessage::PlayerWarped(p) => { - client.x = p.x; - client.y = p.y; - }, - // GameMessage::PlayerChangedFloor(p) => {client.area = MapArea::from_value(&room.mode.episode(), p.map).ok();}, - GameMessage::InitializeSpeechNpc(p) => { - client.x = p.x; - client.z = p.z; - } - _ => {}, - } - } else {} - let m = message.clone(); - Ok(Box::new(client_location.get_client_neighbors(id).await.unwrap().into_iter() - .map(move |client| { - (client.client, SendShipPacket::Message(m.clone())) - }))) + let msg = message.msg.clone(); + clients.with_mut(id, |client| { + let rooms = rooms.clone(); + Box::pin(async move { + match msg { + GameMessage::PlayerChangedMap(p) => { + client.x = p.x; + client.y = p.y; + client.z = p.z; + }, + GameMessage::PlayerChangedMap2(p) => { + client.area = rooms.with(room_id, |room| Box::pin(async move { + room.map_areas.get_area_map(p.map_area).ok() + })).await?; + }, + GameMessage::TellOtherPlayerMyLocation(p) => { + client.x = p.x; + client.y = p.y; + client.z = p.z; + client.area = rooms.with(room_id, |room| Box::pin(async move { + room.map_areas.get_area_map(p.map_area).ok() + })).await?; + }, + GameMessage::PlayerWarpingToFloor(p) => { + client.area = rooms.with(room_id, |room| Box::pin(async move { + room.map_areas.get_area_map(p.area as u16).ok() + })).await?; + }, + GameMessage::PlayerTeleported(p) => { + client.x = p.x; + client.y = p.y; + client.z = p.z; + }, + GameMessage::PlayerStopped(p) => { + client.x = p.x; + client.y = p.y; + client.z = p.z; + }, + GameMessage::PlayerLoadedIn(p) => { + client.x = p.x; + client.y = p.y; + client.z = p.z; + }, + GameMessage::PlayerWalking(p) => { + client.x = p.x; + client.z = p.z; + }, + GameMessage::PlayerRunning(p) => { + client.x = p.x; + client.z = p.z; + }, + GameMessage::PlayerWarped(p) => { + client.x = p.x; + client.y = p.y; + }, + // GameMessage::PlayerChangedFloor(p) => {client.area = MapArea::from_value(&room.mode.episode(), p.map).ok();}, + GameMessage::InitializeSpeechNpc(p) => { + client.x = p.x; + client.z = p.z; + } + _ => {}, + } + Ok::<_, ShipError>(()) + })}).await?; + } + Ok(client_location.get_client_neighbors(id).await?.into_iter() + .map(move |client| { + (client.client, SendShipPacket::Message(message.clone())) + }) + .collect()) } pub async fn charge_attack(id: ClientId, - charge: &ChargeAttack, - mut entity_gateway: EG, + charge: ChargeAttack, + entity_gateway: &mut EG, client_location: &ClientLocation, - clients: &mut Clients, + clients: &Clients, item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static, { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; + let meseta = charge.meseta; + clients.with(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + // TODO: should probably validate this to be a legit number, I'd just hardcode 200 but vjaya + take_meseta(&mut item_state, &mut entity_gateway, &client.character.id, Meseta(meseta)).await + })}).await??; - // TODO: should probably validate this to be a legit number, I'd just hardcode 200 but vjaya - take_meseta(item_state, &mut entity_gateway, &client.character.id, Meseta(charge.meseta)).await?; - - let charge = charge.clone(); - Ok(Box::new(client_location.get_client_neighbors(id).await.unwrap().into_iter() - .map(move |client| { - (client.client, SendShipPacket::Message(Message::new(GameMessage::ChargeAttack(charge.clone())))) - }))) + Ok(client_location.get_client_neighbors(id).await.unwrap().into_iter() + .map(move |client| { + (client.client, SendShipPacket::Message(Message::new(GameMessage::ChargeAttack(charge.clone())))) + }) + .collect()) } pub async fn player_uses_item(id: ClientId, - player_use_tool: &PlayerUseItem, - mut entity_gateway: EG, - _client_location: &ClientLocation, - clients: &mut Clients, - item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + player_use_tool: PlayerUseItem, + entity_gateway: &mut EG, + _client_location: &ClientLocation, + clients: &Clients, + item_state: &mut ItemState) + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static, { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - use_item(item_state, &mut entity_gateway, &mut client.character, &ClientItemId(player_use_tool.item_id), 1).await?; - Ok(Box::new(None.into_iter())) // TODO: should probably tell other players we used an item + clients.with_mut(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + use_item(&mut item_state, &mut entity_gateway, &mut client.character, &ClientItemId(player_use_tool.item_id), 1).await + })}).await??; + Ok(Vec::new()) } pub async fn player_used_medical_center(id: ClientId, - pumc: &PlayerUsedMedicalCenter, - mut entity_gateway: EG, + pumc: PlayerUsedMedicalCenter, + entity_gateway: &mut EG, client_location: &ClientLocation, - clients: &mut Clients, + clients: &Clients, item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static, { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - - take_meseta(item_state, &mut entity_gateway, &client.character.id, Meseta(10)).await?; + clients.with(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + take_meseta(&mut item_state, &mut entity_gateway, &client.character.id, Meseta(10)).await + })}).await??; let pumc = pumc.clone(); - Ok(Box::new(client_location.get_client_neighbors(id).await.unwrap().into_iter() - .map(move |client| { - (client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerUsedMedicalCenter(pumc.clone())))) - }))) + Ok(client_location.get_client_neighbors(id).await.unwrap().into_iter() + .map(move |client| { + (client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerUsedMedicalCenter(pumc.clone())))) + }) + .collect()) } pub async fn player_feed_mag(id: ClientId, - mag_feed: &PlayerFeedMag, - mut entity_gateway: EG, + mag_feed: PlayerFeedMag, + entity_gateway: &mut EG, client_location: &ClientLocation, clients: &Clients, item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static, { - let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - feed_mag(item_state, &mut entity_gateway, &client.character, &ClientItemId(mag_feed.mag_id), &ClientItemId(mag_feed.item_id)).await?; - let mag_feed = mag_feed.clone(); - Ok(Box::new(client_location.get_client_neighbors(id).await.unwrap().into_iter() - .map(move |client| { - (client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerFeedMag(mag_feed.clone())))) - }))) + let cmag_feed = mag_feed.clone(); + clients.with(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + feed_mag(&mut item_state, &mut entity_gateway, &client.character, &ClientItemId(cmag_feed.mag_id), &ClientItemId(cmag_feed.item_id)).await + })}).await??; + + Ok(client_location.get_client_neighbors(id).await.unwrap().into_iter() + .map(move |client| { + (client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerFeedMag(mag_feed.clone())))) + }) + .collect()) } pub async fn player_equips_item(id: ClientId, - pkt: &PlayerEquipItem, - mut entity_gateway: EG, + pkt: PlayerEquipItem, + entity_gateway: &mut EG, clients: &Clients, item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static, { - let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; let equip_slot = if pkt.sub_menu > 0 { ((pkt.sub_menu & 0x7) - 1) % 4 } else { 0 }; - equip_item(item_state, &mut entity_gateway, &client.character, &ClientItemId(pkt.item_id), equip_slot).await?; - Ok(Box::new(None.into_iter())) // TODO: tell other players you equipped an item + + clients.with(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + equip_item(&mut item_state, &mut entity_gateway, &client.character, &ClientItemId(pkt.item_id), equip_slot).await + })}).await??; + Ok(Vec::new()) // TODO: tell other players you equipped an item } pub async fn player_unequips_item(id: ClientId, - pkt: &PlayerUnequipItem, - mut entity_gateway: EG, - clients: &Clients, - item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + pkt: PlayerUnequipItem, + entity_gateway: &mut EG, + clients: &Clients, + item_state: &mut ItemState) + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static, { - let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - unequip_item(item_state, &mut entity_gateway, &client.character, &ClientItemId(pkt.item_id)).await?; - Ok(Box::new(None.into_iter())) // TODO: tell other players if you unequip an item + clients.with(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + unequip_item(&mut item_state, &mut entity_gateway, &client.character, &ClientItemId(pkt.item_id)).await + })}).await??; + Ok(Vec::new()) // TODO: tell other players if you unequip an item } pub async fn player_sorts_items(id: ClientId, - pkt: &SortItems, - mut entity_gateway: EG, + pkt: SortItems, + entity_gateway: &mut EG, clients: &Clients, item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static, { - let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; let item_ids = pkt.item_ids .iter() .filter_map(|item_id| { @@ -390,21 +461,30 @@ where } }) .collect(); - sort_inventory(item_state, &mut entity_gateway, &client.character, item_ids).await?; - Ok(Box::new(None.into_iter())) // TODO: clients probably care about each others item orders + + clients.with(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + sort_inventory(&mut item_state, &mut entity_gateway, &client.character, item_ids).await + })}).await??; + Ok(Vec::new()) // TODO: clients probably care about each others item orders } pub async fn player_sells_item (id: ClientId, - sold_item: &PlayerSoldItem, - mut entity_gateway: EG, - clients: &mut Clients, + sold_item: PlayerSoldItem, + entity_gateway: &mut EG, + clients: &Clients, item_state: &mut ItemState) - -> Result + Send>, anyhow::Error> + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static, { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - sell_item(item_state, &mut entity_gateway, &client.character, ClientItemId(sold_item.item_id), sold_item.amount as u32).await?; - // TODO: send the packet to other clients - Ok(Box::new(None.into_iter())) + clients.with(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + sell_item(&mut item_state, &mut entity_gateway, &client.character, ClientItemId(sold_item.item_id), sold_item.amount as u32).await + })}).await??; + Ok(Vec::new()) // TODO: send the packet to other clients } diff --git a/src/ship/packet/handler/quest.rs b/src/ship/packet/handler/quest.rs index 7f97b7c..8df47fd 100644 --- a/src/ship/packet/handler/quest.rs +++ b/src/ship/packet/handler/quest.rs @@ -1,7 +1,9 @@ use std::io::{Cursor, Read, Seek, SeekFrom}; +use futures::stream::{FuturesOrdered, StreamExt}; use libpso::packet::ship::*; use crate::common::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms}; +use crate::ship::ship::{SendShipPacket, ShipError, Clients}; +use crate::ship::room::Rooms; use crate::ship::location::{ClientLocation, ClientLocationError}; use crate::ship::packet::builder::quest; use libpso::util::array_to_utf8; @@ -36,165 +38,302 @@ fn parse_filename(filename_bytes: &[u8; 16]) -> Result<(u16, u16, QuestFileType) } -pub async fn send_quest_category_list(id: ClientId, rql: &RequestQuestList, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { +pub async fn send_quest_category_list(id: ClientId, + rql: RequestQuestList, + client_location: &ClientLocation, + rooms: &Rooms) + -> Result, ShipError> { let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let room = rooms.get_mut(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; + /* + let mut room = rooms.get_mut(room_id.0) + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? + .write() + .await; let qcl = quest::quest_category_list(&room.quests[rql.flag.clamp(0, (room.quests.len() - 1) as u32) as usize]); room.set_quest_group(rql.flag as usize); Ok(Box::new(vec![(id, SendShipPacket::QuestCategoryList(qcl))].into_iter())) + */ + let rql = rql.clone(); + rooms.with_mut(room_id, |room| Box::pin(async move { + let qcl = quest::quest_category_list(&room.quests[rql.flag.clamp(0, (room.quests.len() - 1) as u32) as usize]); + room.set_quest_group(rql.flag as usize); + Ok(vec![(id, SendShipPacket::QuestCategoryList(qcl))]) + })).await? } -pub async fn select_quest_category(id: ClientId, menuselect: &MenuSelect, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { +pub async fn select_quest_category(id: ClientId, + menuselect: MenuSelect, + client_location: &ClientLocation, + rooms: &Rooms) + -> Result, ShipError> { let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let room = rooms.get_mut(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; - let (_, category_quests) = room.quests[room.quest_group.value()].iter() - .nth(menuselect.item as usize) - .ok_or(ShipError::InvalidQuestCategory(menuselect.item))?; + rooms.with(room_id, |room| Box::pin(async move { + let (_, category_quests) = room.quests[room.quest_group.value()].iter() + .nth(menuselect.item as usize) + .ok_or(ShipError::InvalidQuestCategory(menuselect.item))?; - let ql = quest::quest_list(menuselect.item, category_quests); - for q in ql.quests.clone() { - println!("name: {:?} quest_id: {}", q.name, q.quest_id); - } - Ok(Box::new(vec![(id, SendShipPacket::QuestOptionList(ql))].into_iter())) + let ql = quest::quest_list(menuselect.item, category_quests); + Ok(vec![(id, SendShipPacket::QuestOptionList(ql))]) + })).await? } -pub async fn quest_detail(id: ClientId, questdetailrequest: &QuestDetailRequest, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { +pub async fn quest_detail(id: ClientId, + questdetailrequest: QuestDetailRequest, + client_location: &ClientLocation, + rooms: &Rooms) + -> Result, ShipError> { let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let room = rooms.get_mut(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; - let (_, category_quests) = room.quests[room.quest_group.value()].iter() - .nth(questdetailrequest.category as usize) - .ok_or(ShipError::InvalidQuestCategory(questdetailrequest.category as u32))?; + rooms.with(room_id, |room| Box::pin(async move { + let (_, category_quests) = room.quests[room.quest_group.value()].iter() + .nth(questdetailrequest.category as usize) + .ok_or(ShipError::InvalidQuestCategory(questdetailrequest.category as u32))?; - let quest = category_quests.iter() - .find(|q| { - q.id == questdetailrequest.quest as u16 - }).ok_or(ShipError::InvalidQuest(questdetailrequest.quest as u32))?; + let quest = category_quests.iter() + .find(|q| { + q.id == questdetailrequest.quest as u16 + }).ok_or(ShipError::InvalidQuest(questdetailrequest.quest as u32))?; - let qd = quest::quest_detail(quest); - - Ok(Box::new(vec![(id, SendShipPacket::QuestDetail(qd))].into_iter())) + let qd = quest::quest_detail(quest); + + Ok(vec![(id, SendShipPacket::QuestDetail(qd))]) + })).await? } -pub async fn player_chose_quest(id: ClientId, questmenuselect: &QuestMenuSelect, clients: &mut Clients, client_location: &ClientLocation, rooms: &mut Rooms) - -> Result + Send>, ShipError> { +pub async fn player_chose_quest(id: ClientId, + questmenuselect: QuestMenuSelect, + clients: &Clients, + client_location: &ClientLocation, + rooms: &Rooms) + -> Result, ShipError> { let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let room = rooms.get_mut(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; - let (_, category_quests) = room.quests[room.quest_group.value()].iter() + + let client_location = client_location.clone(); + let questmenuselect = questmenuselect.clone(); + rooms.with_mut(room_id, |room| { + let clients = clients.clone(); + Box::pin(async move { + let quest = room.quests[room.quest_group.value()].iter() + .nth(questmenuselect.category as usize) + .ok_or(ShipError::InvalidQuestCategory(questmenuselect.category as u32))? + .1 + .iter() + .find(|q| { + q.id == questmenuselect.quest as u16 + }) + .ok_or(ShipError::InvalidQuest(questmenuselect.quest as u32))? + .clone(); + + let rare_monster_drops = room.rare_monster_table.clone(); + room.maps.set_quest_data(quest.enemies.clone(), quest.objects.clone(), &rare_monster_drops); + room.map_areas = quest.map_areas.clone(); + + let bin = quest::quest_header(&questmenuselect, &quest.bin_blob, "bin"); + let dat = quest::quest_header(&questmenuselect, &quest.dat_blob, "dat"); + + let area_clients = client_location.get_all_clients_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + for client in &area_clients { + clients.with_mut(client.client, |client| Box::pin(async move { + client.done_loading_quest = false; + })).await?; + } + //area_clients.iter().for_each(|c| { + //if let Some(client) = clients.get_mut(&c.client) { + // client.done_loading_quest = false; + //} + //}); + Ok(area_clients + .into_iter() + .flat_map(move |c| { + vec![(c.client, SendShipPacket::QuestHeader(bin.clone())), (c.client, SendShipPacket::QuestHeader(dat.clone()))] + }) + .collect()) + })}).await? + /* + let mut room = rooms.get(room_id.0) + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? + .as_ref() + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? + .write() + .await; + /* + let (_, category_quests) = room.quests[room.quest_group.value()].iter() .nth(questmenuselect.category as usize) .ok_or(ShipError::InvalidQuestCategory(questmenuselect.category as u32))?; - let quest = category_quests.iter() + let quest = category_quests.iter() .find(|q| { - q.id == questmenuselect.quest as u16 - }).ok_or(ShipError::InvalidQuest(questmenuselect.quest as u32))?; + q.id == questmenuselect.quest as u16 +}).ok_or(ShipError::InvalidQuest(questmenuselect.quest as u32))? + .clone(); + */ - room.maps.set_quest_data(quest.enemies.clone(), quest.objects.clone(), &room.rare_monster_table); - room.map_areas = quest.map_areas.clone(); + let quest = room.quests[room.quest_group.value()].iter() + .nth(questmenuselect.category as usize) + .ok_or(ShipError::InvalidQuestCategory(questmenuselect.category as u32))? + .1 + .iter() + .find(|q| { + q.id == questmenuselect.quest as u16 +}) + .ok_or(ShipError::InvalidQuest(questmenuselect.quest as u32))? + .clone(); - let bin = quest::quest_header(questmenuselect, &quest.bin_blob, "bin"); - let dat = quest::quest_header(questmenuselect, &quest.dat_blob, "dat"); + let rare_monster_drops = room.rare_monster_table.clone(); + room.maps.set_quest_data(quest.enemies.clone(), quest.objects.clone(), &rare_monster_drops); + room.map_areas = quest.map_areas.clone(); - let area_clients = client_location.get_all_clients_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - area_clients.iter().for_each(|c| { + let bin = quest::quest_header(questmenuselect, &quest.bin_blob, "bin"); + let dat = quest::quest_header(questmenuselect, &quest.dat_blob, "dat"); + + let area_clients = client_location.get_all_clients_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + area_clients.iter().for_each(|c| { if let Some(client) = clients.get_mut(&c.client) { - client.done_loading_quest = false; - } - }); - Ok(Box::new(area_clients.into_iter().flat_map(move |c| { + client.done_loading_quest = false; +} +}); + Ok(Box::new(area_clients.into_iter().flat_map(move |c| { vec![(c.client, SendShipPacket::QuestHeader(bin.clone())), (c.client, SendShipPacket::QuestHeader(dat.clone()))] - }))) +}))) + */ } -pub async fn quest_file_request(id: ClientId, quest_file_request: &QuestFileRequest, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { +pub async fn quest_file_request(id: ClientId, + quest_file_request: QuestFileRequest, + client_location: &ClientLocation, + rooms: &mut Rooms) + -> Result, ShipError> +{ let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let room = rooms.get_mut(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() + + let quest_file_request = quest_file_request.clone(); + rooms.with(room_id, |room| Box::pin(async move { + let (category_id, quest_id, datatype) = parse_filename(&quest_file_request.filename)?; + let (_, category_quests) = room.quests[room.quest_group.value()].iter() + .nth(category_id as usize) + .ok_or(ShipError::InvalidQuestCategory(category_id as u32))?; + + let quest = category_quests.iter() + .find(|q| { + q.id == quest_id as u16 + }).ok_or(ShipError::InvalidQuest(quest_id as u32))?; + + let blob = match datatype { + QuestFileType::Bin => &quest.bin_blob, + QuestFileType::Dat => &quest.dat_blob, + }; + let mut blob_cursor = Cursor::new(&**blob); + + let mut subblob = [0u8; 0x400]; + let blob_length = blob_cursor.read(&mut subblob)?; + let qc = quest::quest_chunk(0, quest_file_request.filename, subblob, blob_length); + + Ok(vec![(id, SendShipPacket::QuestChunk(qc))]) + })).await? +} + +pub async fn quest_chunk_ack(id: ClientId, + quest_chunk_ack: QuestChunkAck, + client_location: &ClientLocation, + rooms: &Rooms) + -> Result, ShipError> { + let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + + let quest_chunk_ack = quest_chunk_ack.clone(); + rooms.with(room_id, |room| Box::pin(async move { + let (category_id, quest_id, datatype) = parse_filename(&quest_chunk_ack.filename)?; + let (_, category_quests) = room.quests[room.quest_group.value()].iter() + .nth(category_id as usize) + .ok_or(ShipError::InvalidQuestCategory(category_id as u32))?; + + let quest = category_quests.iter() + .find(|q| { + q.id == quest_id + }).ok_or(ShipError::InvalidQuest(quest_id as u32))?; + + let blob = match datatype { + QuestFileType::Bin => &quest.bin_blob, + QuestFileType::Dat => &quest.dat_blob, + }; + + let mut blob_cursor = Cursor::new(&**blob); + blob_cursor.seek(SeekFrom::Start((quest_chunk_ack.chunk_num as u64 + 1) * 0x400))?; + let mut subblob = [0u8; 0x400]; + let blob_length = blob_cursor.read(&mut subblob)?; + if blob_length == 0 { + return Ok(Vec::new()); + } + let qc = quest::quest_chunk(quest_chunk_ack.chunk_num + 1, quest_chunk_ack.filename, subblob, blob_length); + + Ok(vec![(id, SendShipPacket::QuestChunk(qc))]) + })).await? + + /* + let mut room = rooms.get(room_id.0) + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? + .write() + .await + .as_ref() .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; - let (category_id, quest_id, datatype) = parse_filename(&quest_file_request.filename)?; - let (_, category_quests) = room.quests[room.quest_group.value()].iter() + let (category_id, quest_id, datatype) = parse_filename(&quest_chunk_ack.filename)?; + let (_, category_quests) = room.quests[room.quest_group.value()].iter() .nth(category_id as usize) .ok_or(ShipError::InvalidQuestCategory(category_id as u32))?; - let quest = category_quests.iter() + let quest = category_quests.iter() .find(|q| { - q.id == quest_id as u16 - }).ok_or(ShipError::InvalidQuest(quest_id as u32))?; + q.id == quest_id +}).ok_or(ShipError::InvalidQuest(quest_id as u32))?; - let blob = match datatype { + let blob = match datatype { QuestFileType::Bin => &quest.bin_blob, QuestFileType::Dat => &quest.dat_blob, - }; - let mut blob_cursor = Cursor::new(blob); +}; - let mut subblob = [0u8; 0x400]; - let blob_length = blob_cursor.read(&mut subblob)?; - let qc = quest::quest_chunk(0, quest_file_request.filename, subblob, blob_length); - - Ok(Box::new(vec![(id, SendShipPacket::QuestChunk(qc))].into_iter())) -} - -pub async fn quest_chunk_ack(id: ClientId, quest_chunk_ack: &QuestChunkAck, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { - let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let room = rooms.get_mut(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; - - let (category_id, quest_id, datatype) = parse_filename(&quest_chunk_ack.filename)?; - let (_, category_quests) = room.quests[room.quest_group.value()].iter() - .nth(category_id as usize) - .ok_or(ShipError::InvalidQuestCategory(category_id as u32))?; - - let quest = category_quests.iter() - .find(|q| { - q.id == quest_id - }).ok_or(ShipError::InvalidQuest(quest_id as u32))?; - - let blob = match datatype { - QuestFileType::Bin => &quest.bin_blob, - QuestFileType::Dat => &quest.dat_blob, - }; - - let mut blob_cursor = Cursor::new(blob); - blob_cursor.seek(SeekFrom::Start((quest_chunk_ack.chunk_num as u64 + 1) * 0x400))?; - let mut subblob = [0u8; 0x400]; - let blob_length = blob_cursor.read(&mut subblob)?; - if blob_length == 0 { + let mut blob_cursor = Cursor::new(&**blob); + blob_cursor.seek(SeekFrom::Start((quest_chunk_ack.chunk_num as u64 + 1) * 0x400))?; + let mut subblob = [0u8; 0x400]; + let blob_length = blob_cursor.read(&mut subblob)?; + if blob_length == 0 { return Ok(Box::new(None.into_iter())); - } - let qc = quest::quest_chunk(quest_chunk_ack.chunk_num + 1, quest_chunk_ack.filename, subblob, blob_length); - - Ok(Box::new(vec![(id, SendShipPacket::QuestChunk(qc))].into_iter())) +} + let qc = quest::quest_chunk(quest_chunk_ack.chunk_num + 1, quest_chunk_ack.filename, subblob, blob_length); + + Ok(Box::new(vec![(id, SendShipPacket::QuestChunk(qc))].into_iter())) + */ } -pub async fn done_loading_quest(id: ClientId, clients: &mut Clients, client_location: &ClientLocation) - -> Result + Send>, ShipError> { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - client.done_loading_quest = true; +pub async fn done_loading_quest(id: ClientId, + clients: &Clients, + client_location: &ClientLocation) + -> Result, ShipError> { + clients.with_mut(id, |client| Box::pin(async move { + client.done_loading_quest = true; + })).await?; let area_clients = client_location.get_all_clients_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let all_loaded = area_clients.iter().all(|c| { - clients.get(&c.client) - .map(|client| { - client.done_loading_quest - }) - .unwrap_or(false) - }); + let all_loaded = area_clients.iter() + .map(|client| async { + clients.with(client.client, |client| Box::pin(async move { + client.done_loading_quest + })) + }) + .collect::>() + .all(|c| async move { + c.await.unwrap_or(false) + }).await; + if all_loaded { - Ok(Box::new(area_clients.into_iter().map(|c| { - (c.client, SendShipPacket::DoneLoadingQuest(DoneLoadingQuest {})) - }))) + Ok(area_clients + .iter() + .map(|c| { + (c.client, SendShipPacket::DoneLoadingQuest(DoneLoadingQuest {})) + }) + .collect()) } else { - Ok(Box::new(None.into_iter())) + Ok(Vec::new()) } } diff --git a/src/ship/packet/handler/room.rs b/src/ship/packet/handler/room.rs index 3a02102..ab3e79a 100644 --- a/src/ship/packet/handler/room.rs +++ b/src/ship/packet/handler/room.rs @@ -2,132 +2,186 @@ use libpso::packet::ship::*; use libpso::packet::messages::*; use crate::common::serverstate::ClientId; use crate::common::leveltable::LEVEL_TABLE; -use crate::ship::ship::{SendShipPacket, ShipError, Rooms, Clients}; -use crate::ship::location::{ClientLocation, RoomId, RoomLobby, ClientLocationError}; +use crate::ship::ship::{SendShipPacket, ShipError, Clients}; +use crate::ship::room::Rooms; +use crate::ship::location::{ClientLocation, RoomId, RoomLobby, ClientLocationError, GetAreaError}; use crate::ship::packet::builder; use crate::ship::room; use crate::ship::items::state::ItemState; -use std::convert::{TryFrom}; -use futures::StreamExt; +use std::convert::{TryFrom, Into}; +use async_std::sync::{Arc, RwLock}; +use futures::stream::{FuturesOrdered, StreamExt}; pub async fn create_room(id: ClientId, - create_room: &CreateRoom, + create_room: CreateRoom, client_location: &mut ClientLocation, - clients: &mut Clients, + clients: &Clients, item_state: &mut ItemState, - rooms: &mut Rooms) - -> Result + Send>, anyhow::Error> { - let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - let level = LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp); + rooms: &Rooms) + -> Result, ShipError> { + let level = clients.with(id, |client| Box::pin(async move { + LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp) + })).await?; match room::Difficulty::try_from(create_room.difficulty)? { - room::Difficulty::Ultimate => { - if level < 80 { - return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 80 \nto create Ultimate rooms.".into())))].into_iter())) - } + room::Difficulty::Ultimate if level < 80 => { + return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 80 \nto create Ultimate rooms.".into())))]) }, - room::Difficulty::VeryHard => { - if level < 40 { - return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 40 \nto create Very Hard rooms.".into())))].into_iter())) - } + room::Difficulty::VeryHard if level < 40 => { + return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 40 \nto create Very Hard rooms.".into())))]) }, - room::Difficulty::Hard => { - if level < 20 { - return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 20 \nto create Hard rooms.".into())))].into_iter())) - } + room::Difficulty::Hard if level < 20 => { + return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 20 \nto create Hard rooms.".into())))]) }, - room::Difficulty::Normal => {}, + _ => {}, }; - let area = client_location.get_area(id).await.unwrap(); - let area_client = client_location.get_local_client(id).await.unwrap(); - let lobby_neighbors = client_location.get_client_neighbors(id).await.unwrap(); - let room_id = client_location.create_new_room(id).await.unwrap(); - let mut room = room::RoomState::from_create_room(create_room, client.character.section_id).unwrap(); - room.bursting = true; + let area = client_location.get_area(id).await?; + let area_client = client_location.get_local_client(id).await?; + let lobby_neighbors = client_location.get_client_neighbors(id).await?; - item_state.add_character_to_room(room_id, &client.character, area_client); + //let room_id = client_location.create_new_room(id).await.map_err(Into::::into)?; + let room_id = client_location.create_new_room(id).await?; + let room = clients.with(id, |client| { + let mut item_state = item_state.clone(); + Box::pin(async move { + item_state.add_character_to_room(room_id, &client.character, area_client).await; + let mut room = room::RoomState::from_create_room(&create_room, client.character.section_id)?; + room.bursting = true; + Ok::<_, ShipError>(room) + })}).await??; let join_room = builder::room::join_room(id, clients, client_location, room_id, &room).await?; - rooms[room_id.0] = Some(room); + rooms.add(room_id, room).await?; - let mut result: Box + Send> = Box::new( - vec![(id, SendShipPacket::JoinRoom(join_room))].into_iter() - ); + let mut result = vec![(id, SendShipPacket::JoinRoom(join_room))]; if let Ok(leader) = client_location.get_area_leader(area).await { let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())); - result = Box::new(result.chain(lobby_neighbors - .into_iter() - .map(move |c| { - (c.client, leave_lobby.clone()) - }))); + result.extend(lobby_neighbors + .into_iter() + .map(move |c| { + (c.client, leave_lobby.clone()) + })); } Ok(result) } +// TODO: remove unwraps pub async fn room_name_request(id: ClientId, client_location: &ClientLocation, rooms: &Rooms) - -> Box + Send> { - let area = client_location.get_area(id).await.unwrap(); + -> Result, ShipError> { + let area = client_location.get_area(id).await?; match area { - RoomLobby::Room(room) => Box::new(vec![(id, SendShipPacket::RoomNameResponse(RoomNameResponse {name: rooms[room.0].as_ref().unwrap().name.clone()}))].into_iter()), - RoomLobby::Lobby(_) => panic!() + RoomLobby::Room(room) => { + rooms.with(room, |room| Box::pin(async move { + vec![(id, SendShipPacket::RoomNameResponse(RoomNameResponse { + name: room.name.clone() + }))] + })).await + }, + RoomLobby::Lobby(_) => Err(GetAreaError::NotInRoom.into()) + //RoomLobby::Lobby(_) => Err(ShipError::ClientLocationError(GetAreaError::NotInRoom)) } } pub async fn join_room(id: ClientId, - pkt: &MenuSelect, + pkt: MenuSelect, client_location: &mut ClientLocation, - clients: &mut Clients, + clients: &Clients, item_state: &mut ItemState, - rooms: &mut Rooms) - -> Result + Send>, ShipError> { - let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - let level = LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp); - // let room = rooms.get(pkt.item as usize).ok_or(ShipError::InvalidRoom(pkt.item))?.as_ref().unwrap(); // clippy look what you made me do - if let Some(room) = rooms.get(pkt.item as usize).ok_or(ShipError::InvalidRoom(pkt.item))? { + rooms: &Rooms) + -> Result, ShipError> { + let room_id = RoomId(pkt.item as usize); + if !rooms.exists(room_id).await { + return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("This room no longer exists!".into())))]) + } + let level = clients.with(id, |client| Box::pin(async move { + LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp) + })).await?; + let (difficulty, bursting) = rooms.with(room_id, |room| Box::pin(async move { + (room.mode.difficulty(), room.bursting) + })).await?; - match room.mode.difficulty() { - room::Difficulty::Ultimate => { - if level < 80 { - return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 80 \nto join Ultimate rooms.".into())))].into_iter())) - } - }, - room::Difficulty::VeryHard => { - if level < 40 { - return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 40 \nto join Very Hard rooms.".into())))].into_iter())) - } - }, - room::Difficulty::Hard => { - if level < 20 { - return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 20 \nto join Hard rooms.".into())))].into_iter())) - } - }, - _ => {}, - }; + match difficulty { + room::Difficulty::Ultimate if level < 80 => { + return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 80 \nto join Ultimate rooms.".into())))]) + }, + room::Difficulty::VeryHard if level < 40 => { + return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 40 \nto join Very Hard rooms.".into())))]) + }, + room::Difficulty::Hard if level < 20 => { + return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 20 \nto join Hard rooms.".into())))]) + }, + _ => {}, + } - let original_area = client_location.get_area(id).await.unwrap(); - let original_neighbors = client_location.get_client_neighbors(id).await.unwrap(); - if room.bursting { - return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("player is bursting\nplease wait".into())))].into_iter())) - } - let room_id = RoomId(pkt.item as usize); - let original_room_clients = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; - client_location.add_client_to_room(id, room_id).await.unwrap(); // TODO: show room full error or whatever + if bursting { + return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("player is bursting\nplease wait".into())))]) + } - let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let original_area = client_location.get_area(id).await?; + let original_neighbors = client_location.get_client_neighbors(id).await?; + let original_room_clients = client_location.get_clients_in_room(room_id).await?; + client_location.add_client_to_room(id, room_id).await?; + let area_client = client_location.get_local_client(id).await?; + //let original_leader = client_location.get_area_leader(original_area).await.unwrap(); + let room_leader = client_location.get_room_leader(room_id).await.unwrap(); - item_state.add_character_to_room(room_id, &client.character, area_client); + clients.with(id, |client| { + let mut item_state = item_state.clone(); + Box::pin(async move { + item_state.add_character_to_room(room_id, &client.character, area_client).await; + })}).await?; - let leader = client_location.get_room_leader(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let join_room = builder::room::join_room(id, clients, client_location, room_id, room).await?; - let add_to = builder::room::add_to_room(id, client, &area_client, &leader, item_state, room_id)?; + let join_room = rooms.with(room_id, |room| { + let clients = clients.clone(); + let client_location = client_location.clone(); + Box::pin(async move { + builder::room::join_room(id, &clients, &client_location, room_id, &room).await + })}).await??; + let add_to = clients.with(id, |client| { + let item_state = item_state.clone(); + Box::pin(async move { + builder::room::add_to_room(id, client, &area_client, &room_leader, &item_state, room_id).await + })}).await??; + //let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), original_leader.local_client.id())); - let room = rooms.get_mut(room_id.0).unwrap().as_mut().unwrap(); + rooms.with_mut(room_id, |room| Box::pin(async move { room.bursting = true; + })).await?; + + Ok(vec![(id, SendShipPacket::JoinRoom(join_room))] + .into_iter() + .chain(original_room_clients.into_iter() + .map(move |c| (c.client, SendShipPacket::AddToRoom(add_to.clone())))) + .chain(futures::stream::iter(original_neighbors.into_iter()) + .filter_map(|c| { + let client_location = client_location.clone(); + async move { + client_location.get_area_leader(original_area).await.ok().map(|leader| { + let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())); + (c.client, leave_lobby.clone()) + }) + } + }) + .collect::>() + .await + ) + .collect()) + /* + if let Ok(leader) = client_location.get_area_leader(original_area).await { + let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())); + result.extend(original_neighbors.into_iter() + .map(move |c| (c.client, leave_lobby.clone()))) + } + */ + + //Ok(result) + /* + + if let Some(room) = &mut *rooms.get(pkt.item as usize).ok_or(ShipError::InvalidRoom(pkt.item))?.write().await { let mut result: Box + Send> = Box::new( vec![(id, SendShipPacket::JoinRoom(join_room))] .into_iter() @@ -141,64 +195,61 @@ pub async fn join_room(id: ClientId, .map(move |c| (c.client, leave_lobby.clone())))) } - Ok(result) + Ok(result.collect()) } else { - Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Game is no longer active".into())))].into_iter())) + Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Game is no longer active".into())))]) } + */ } pub async fn done_bursting(id: ClientId, client_location: &ClientLocation, - rooms: &mut Rooms) - -> Box + Send> { - let area = client_location.get_area(id).await.unwrap(); - let mut rare_monster_list: Option> = None; - if let RoomLobby::Room(room_id) = area { - if let Some(room) = rooms.get_mut(room_id.0).unwrap().as_mut() { - room.bursting = false; - rare_monster_list = Some(room.maps.get_rare_monster_list()); - }; - } - let area_client = client_location.get_local_client(id).await.unwrap(); // TODO: unwrap - let mut result: Box + Send> = Box::new( - client_location.get_client_neighbors(id).await.unwrap().into_iter() // TODO: unwrap - .flat_map(move |client| { - vec![ - (client.client, SendShipPacket::Message(Message::new(GameMessage::BurstDone(BurstDone { - client: area_client.local_client.id(), - target: 0 - })))), - ] - }) - ); + rooms: &Rooms) + -> Result, ShipError> { + let room_id = client_location.get_room(id).await?; + let rare_monster_list = rooms.with_mut(room_id, |room| Box::pin(async move { + room.bursting = false; + room.maps.get_rare_monster_list() + })).await?; - // TODO: check how often `done_bursting` is called. ie: make sure it's only used when joining a room and not each time a player warps in a pipe - if let Some(rare_list) = rare_monster_list { - let rare_monster_packet = SendShipPacket::RareMonsterList(builder::room::build_rare_monster_list(rare_list)); - result = Box::new(result.chain(vec![(id, rare_monster_packet)])); // TODO: make sure we arent clobbering `result` here - } - - result + let area_client = client_location.get_local_client(id).await?; + Ok(client_location.get_client_neighbors(id).await?.into_iter() + .map(move |client| { + (client.client, SendShipPacket::Message(Message::new(GameMessage::BurstDone(BurstDone { + client: area_client.local_client.id(), + target: 0 + })))) + }) + .chain(std::iter::once_with(move || { + (id, SendShipPacket::RareMonsterList(builder::room::build_rare_monster_list(rare_monster_list))) + })) + .collect()) } pub async fn request_room_list(id: ClientId, client_location: &ClientLocation, rooms: &Rooms) - -> Box + Send> { - let active_room_list = futures::stream::iter(rooms.iter()) + -> Vec<(ClientId, SendShipPacket)> { + //let active_room_list = futures::stream::iter(rooms.iter()) + let active_room_list = rooms.stream() .enumerate() .filter_map(|(i, r)| async move { - r.as_ref().map(|room| async move { - RoomList { - menu_id: ROOM_MENU_ID, - item_id: i as u32, - difficulty: room.get_difficulty_for_room_list(), - players: client_location.get_clients_in_room(RoomId(i)).await.unwrap().len() as u8, - name: libpso::utf8_to_utf16_array!(room.name, 16), - episode: room.get_episode_for_room_list(), - flags: room.get_flags_for_room_list(), - } - }) + r.as_ref().map(|room| { + let difficulty = room.get_difficulty_for_room_list(); + let name = libpso::utf8_to_utf16_array!(room.name, 16); + let episode = room.get_episode_for_room_list(); + let flags = room.get_flags_for_room_list(); + async move { + RoomList { + menu_id: ROOM_MENU_ID, + item_id: i as u32, + difficulty, + players: client_location.get_clients_in_room(RoomId(i)).await.unwrap().len() as u8, + name, + episode, + flags, + } + }}) }); let baseroom: RoomList = RoomList { menu_id: ROOM_MENU_ID, @@ -210,21 +261,26 @@ pub async fn request_room_list(id: ClientId, flags: 0, }; - Box::new(vec![(id, SendShipPacket::RoomListResponse(RoomListResponse { + vec![(id, SendShipPacket::RoomListResponse(RoomListResponse { baseroom, rooms: futures::future::join_all(active_room_list.collect::>().await).await - }))].into_iter()) + }))] } pub async fn cool_62(id: ClientId, - cool_62: &Like62ButCooler, + cool_62: Like62ButCooler, client_location: &ClientLocation) - -> Box + Send> { + -> Vec<(ClientId, SendShipPacket)> { let target = cool_62.flag as u8; let cool_62 = cool_62.clone(); - Box::new(client_location.get_client_neighbors(id).await.unwrap().into_iter() - .filter(move |client| client.local_client.id() == target) - .map(move |client| { - (client.client, SendShipPacket::Like62ButCooler(cool_62.clone())) - })) + client_location + .get_client_neighbors(id) + .await + .unwrap() + .into_iter() + .filter(move |client| client.local_client.id() == target) + .map(move |client| { + (client.client, SendShipPacket::Like62ButCooler(cool_62.clone())) + }) + .collect() } diff --git a/src/ship/packet/handler/settings.rs b/src/ship/packet/handler/settings.rs index 52b0e8f..58eea70 100644 --- a/src/ship/packet/handler/settings.rs +++ b/src/ship/packet/handler/settings.rs @@ -3,47 +3,70 @@ use crate::common::serverstate::ClientId; use crate::ship::ship::{SendShipPacket, ShipError, Clients}; use crate::entity::gateway::EntityGateway; -pub async fn update_config(id: ClientId, - update_config: &UpdateConfig, - clients: &mut Clients, - mut entity_gateway: EG) - -> Box + Send> { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); - client.character.config.update(update_config); - entity_gateway.save_character(&client.character).await.unwrap(); - Box::new(None.into_iter()) +pub async fn update_config(id: ClientId, + update_config: UpdateConfig, + clients: &Clients, + entity_gateway: &mut EG) + -> Result, ShipError> +where + EG: EntityGateway + Clone + 'static, +{ + clients.with_mut(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + Box::pin(async move { + client.character.config.update(&update_config); + entity_gateway.save_character(&client.character).await + })}).await??; + Ok(Vec::new()) } -pub async fn save_options(id: ClientId, - save_options: &SaveOptions, - clients: &mut Clients, - mut entity_gateway: EG) - -> Box + Send> { - // TODO: don't unwrap? - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); - client.character.option_flags = save_options.options; - entity_gateway.save_character(&client.character).await.unwrap(); - Box::new(None.into_iter()) +pub async fn save_options(id: ClientId, + save_options: SaveOptions, + clients: &Clients, + entity_gateway: &mut EG) + -> Result, ShipError> +where + EG: EntityGateway + Clone + 'static, +{ + clients.with_mut(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + Box::pin(async move { + client.character.option_flags = save_options.options; + entity_gateway.save_character(&client.character).await + })}).await??; + Ok(Vec::new()) } -pub async fn keyboard_config(id: ClientId, - keyboard_config: &KeyboardConfig, - clients: &mut Clients, - mut entity_gateway: EG) - -> Box + Send> { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); - client.character.keyboard_config.update(keyboard_config); - entity_gateway.save_character(&client.character).await.unwrap(); - Box::new(None.into_iter()) +pub async fn keyboard_config(id: ClientId, + keyboard_config: KeyboardConfig, + clients: &Clients, + entity_gateway: &mut EG) + -> Result, ShipError> +where + EG: EntityGateway + Clone + 'static, +{ + clients.with_mut(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + Box::pin(async move { + client.character.keyboard_config.update(&keyboard_config); + entity_gateway.save_character(&client.character).await + })}).await??; + Ok(Vec::new()) } -pub async fn gamepad_config(id: ClientId, - gamepad_config: &GamepadConfig, - clients: &mut Clients, - mut entity_gateway: EG) - -> Box + Send> { - let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); - client.character.gamepad_config.update(gamepad_config); - entity_gateway.save_character(&client.character).await.unwrap(); - Box::new(None.into_iter()) +pub async fn gamepad_config(id: ClientId, + gamepad_config: GamepadConfig, + clients: &Clients, + entity_gateway: &mut EG) + -> Result, ShipError> +where + EG: EntityGateway + Clone + 'static, +{ + clients.with_mut(id, |client| { + let mut entity_gateway = entity_gateway.clone(); + Box::pin(async move { + client.character.gamepad_config.update(&gamepad_config); + entity_gateway.save_character(&client.character).await + })}).await??; + Ok(Vec::new()) } diff --git a/src/ship/packet/handler/ship.rs b/src/ship/packet/handler/ship.rs index 0a0c0cd..b9505f3 100644 --- a/src/ship/packet/handler/ship.rs +++ b/src/ship/packet/handler/ship.rs @@ -5,19 +5,17 @@ use crate::common::interserver::Ship; use crate::ship::ship::{SendShipPacket, ShipError}; use crate::ship::packet::builder; -pub fn ship_list(id: ClientId, ship_list: &[Ship]) - -> Box + Send> { - Box::new(vec![(id, SendShipPacket::ShipList(builder::ship::ship_list(ship_list)))].into_iter()) +pub fn ship_list(id: ClientId, ship_list: &[Ship]) -> Vec<(ClientId, SendShipPacket)> { + vec![(id, SendShipPacket::ShipList(builder::ship::ship_list(ship_list)))] } -pub fn block_list(id: ClientId, shipname: &str, num_blocks: usize) - -> Box + Send> { - Box::new(vec![(id, SendShipPacket::ShipBlockList(ShipBlockList::new(shipname, num_blocks)))].into_iter()) +pub fn block_list(id: ClientId, shipname: &str, num_blocks: usize) -> Vec<(ClientId, SendShipPacket)> { + vec![(id, SendShipPacket::ShipBlockList(ShipBlockList::new(shipname, num_blocks)))] } -pub fn selected_ship(id: ClientId, menuselect: &MenuSelect, ship_list: &[Ship]) - -> Result + Send>, ShipError> { +pub fn selected_ship(id: ClientId, menuselect: MenuSelect, ship_list: &[Ship]) + -> Result, ShipError> { let ship = ship_list.get(menuselect.item as usize).ok_or(ShipError::InvalidShip(menuselect.item as usize))?; let ip = u32::from_ne_bytes(ship.ip.octets()); - Ok(Box::new(vec![(id, SendShipPacket::RedirectClient(RedirectClient::new(ip, ship.port)))].into_iter())) + Ok(vec![(id, SendShipPacket::RedirectClient(RedirectClient::new(ip, ship.port)))]) } diff --git a/src/ship/packet/handler/trade.rs b/src/ship/packet/handler/trade.rs index 8710d72..b7b6cd5 100644 --- a/src/ship/packet/handler/trade.rs +++ b/src/ship/packet/handler/trade.rs @@ -50,32 +50,35 @@ pub enum TradeError { -pub async fn do_trade_action(id: ClientId, - pkt: TradeRequest, - client_location: &ClientLocation, - target: u32, - this: &mut ClientTradeState, - other: &mut ClientTradeState, - action: F) -> Result + Send>, ShipError> +async fn do_trade_action(id: ClientId, + pkt: TradeRequest, + client_location: &ClientLocation, + target: u32, + this: &mut ClientTradeState, + other: &mut ClientTradeState, + action: F) + -> Result, ShipError> where F: Fn(&mut ClientTradeState, &mut ClientTradeState) -> Result<(), ShipError>, { Ok(match action(this, other) { Ok(_) => { - Box::new(client_location.get_all_clients_by_client(id).await?.into_iter() - .filter(move |client| client.local_client.id() == target as u8) - .map(move |client| { - (client.client, SendShipPacket::DirectMessage(DirectMessage::new(target, GameMessage::TradeRequest(pkt.clone())))) - })) + client_location.get_all_clients_by_client(id).await?.into_iter() + .filter(move |client| client.local_client.id() == target as u8) + .map(move |client| { + (client.client, SendShipPacket::DirectMessage(DirectMessage::new(target, GameMessage::TradeRequest(pkt.clone())))) + }) + .collect() }, Err(_) => { // TODO: some sort of error logging? - Box::new(client_location.get_all_clients_by_client(id).await?.into_iter() - .filter(move |client| client.local_client.id() == target as u8) - .map(move |client| { - (client.client, SendShipPacket::CancelTrade(CancelTrade {})) - }) - .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {}))))) + client_location.get_all_clients_by_client(id).await?.into_iter() + .filter(move |client| client.local_client.id() == target as u8) + .map(move |client| { + (client.client, SendShipPacket::CancelTrade(CancelTrade {})) + }) + .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {})))) + .collect() } }) } @@ -83,13 +86,13 @@ where // TODO: remove target pub async fn trade_request(id: ClientId, - trade_request: &TradeRequest, + trade_request: TradeRequest, target: u32, client_location: &ClientLocation, - clients: &mut Clients, + clients: &Clients, item_state: &mut ItemState, trades: &mut TradeState) - -> Result + Send>, ShipError> + -> Result, ShipError> { let trade_request = trade_request.clone(); // TODO: make this function take ownership of packet match trade_request.trade { @@ -109,11 +112,12 @@ pub async fn trade_request(id: ClientId, return Err(TradeError::OtherAlreadyInTrade.into()) } trades.new_trade(&id, &trade_partner.client); - Ok(Box::new(client_location.get_all_clients_by_client(id).await?.into_iter() - .filter(move |client| client.local_client.id() == target as u8) - .map(move |client| { - (client.client, SendShipPacket::DirectMessage(DirectMessage::new(target, GameMessage::TradeRequest(trade_request.clone())))) - }))) + Ok(client_location.get_all_clients_by_client(id).await?.into_iter() + .filter(move |client| client.local_client.id() == target as u8) + .map(move |client| { + (client.client, SendShipPacket::DirectMessage(DirectMessage::new(target, GameMessage::TradeRequest(trade_request.clone())))) + }) + .collect()) }, TradeRequestInitializeCommand::Respond => { trades @@ -139,10 +143,13 @@ pub async fn trade_request(id: ClientId, .with(&id, |mut this, mut other| { let trade_request = trade_request.clone(); async move { + let inventory = clients.with(this.client(), |client| { + let item_state = item_state.clone(); + Box::pin(async move { + item_state.get_character_inventory(&client.character).await + })}).await??; do_trade_action(id, trade_request, client_location, target, &mut this, &mut other, |this, other| { if this.status == TradeStatus::Trading && other.status == TradeStatus::Trading { - let client = clients.get(&this.client()).ok_or_else(|| ShipError::ClientNotFound(this.client()))?; - let inventory = item_state.get_character_inventory(&client.character)?; if ClientItemId(item_id) == MESETA_ITEM_ID { this.meseta += amount as usize; } @@ -174,10 +181,13 @@ pub async fn trade_request(id: ClientId, .with(&id, |mut this, mut other| { let trade_request = trade_request.clone(); async move { + let inventory = clients.with(this.client(), |client| { + let item_state = item_state.clone(); + Box::pin(async move { + item_state.get_character_inventory(&client.character).await + })}).await??; do_trade_action(id, trade_request, client_location, target, &mut this, &mut other, |this, other| { if this.status == TradeStatus::Trading && other.status == TradeStatus::Trading { - let client = clients.get(&this.client()).ok_or_else(|| ShipError::ClientNotFound(this.client()))?; - let inventory = item_state.get_character_inventory(&client.character)?; if ClientItemId(item_id) == MESETA_ITEM_ID { this.meseta -= amount as usize; } @@ -256,13 +266,14 @@ pub async fn trade_request(id: ClientId, }).await? }, TradeRequestCommand::Cancel => { - trades.remove_trade(&id); - Ok(Box::new(client_location.get_all_clients_by_client(id).await?.into_iter() - .filter(move |client| client.local_client.id() == target as u8) - .map(move |client| { - (client.client, SendShipPacket::CancelTrade(CancelTrade {})) - }) - .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {})))))) + trades.remove_trade(&id).await; + Ok(client_location.get_all_clients_by_client(id).await?.into_iter() + .filter(move |client| client.local_client.id() == target as u8) + .map(move |client| { + (client.client, SendShipPacket::CancelTrade(CancelTrade {})) + }) + .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {})))) + .collect()) } } } @@ -276,23 +287,32 @@ fn status_is_not(status: &TradeStatus, statuses: &[TradeStatus; !status_is(status, statuses) } -pub async fn inner_items_to_trade(id: ClientId, - items_to_trade: &ItemsToTrade, - client_location: &ClientLocation, - clients: &mut Clients, - item_state: &mut ItemState, - trades: &mut TradeState) - -> Result + Send>, ShipError> +async fn inner_items_to_trade(id: ClientId, + items_to_trade: ItemsToTrade, + client_location: &ClientLocation, + clients: &Clients, + item_state: &mut ItemState, + trades: &mut TradeState) + -> Result, ShipError> { - let pkts: Result + Send>, ShipError> = trades + let pkts = trades .with(&id, |mut this, other| async move { if status_is_not(&this.status, &[TradeStatus::FinalConfirm]) || status_is_not(&other.status, &[TradeStatus::FinalConfirm, TradeStatus::ItemsChecked]) { - return Err(TradeError::MismatchedStatus.into()) + return Err(ShipError::from(TradeError::MismatchedStatus)) } - - let client = clients.get(&this.client()).ok_or_else(|| ShipError::ClientNotFound(this.client()))?; - let other_client = clients.get(&other.client()).ok_or_else(|| ShipError::ClientNotFound(other.client()))?; - let inventory = item_state.get_character_inventory(&client.character)?; + let other_client = other.client(); + let (this_inventory, other_inventory) = clients.with(this.client(), |client| { + let item_state = item_state.clone(); + let clients = clients.clone(); + Box::pin(async move { + let this = item_state.get_character_inventory(&client.character).await?; + let other_inventory = clients.with(other_client, |client| { + let item_state = item_state.clone(); + Box::pin(async move { + item_state.get_character_inventory(&client.character).await + })}).await??; + Ok::<_, ShipError>((this, other_inventory)) + })}).await??; if items_to_trade.count as usize != (this.items.len() + (if this.meseta != 0 { 1 } else { 0 })) { return Err(TradeError::MismatchedTradeItems.into()) @@ -307,8 +327,8 @@ pub async fn inner_items_to_trade(id: ClientId, return Err(TradeError::InvalidItemId(ClientItemId(item.item_id)).into()) } let amount = u32::from_le_bytes(item.item_data2); - let character_meseta = item_state.get_character_inventory(&client.character).map_err(|_| TradeError::InvalidMeseta)?.meseta; - let other_character_meseta = item_state.get_character_inventory(&other_client.character).map_err(|_| TradeError::InvalidMeseta)?.meseta; + let character_meseta = this_inventory.meseta; + let other_character_meseta = other_inventory.meseta; if amount > character_meseta.0 { return Err(TradeError::InvalidMeseta.into()) } @@ -321,7 +341,7 @@ pub async fn inner_items_to_trade(id: ClientId, Ok(()) } else { - let real_item = inventory.get_by_client_id(&ClientItemId(item.item_id)) + let real_item = this_inventory.get_by_client_id(&ClientItemId(item.item_id)) .ok_or(ItemStateError::InvalidItemId(ClientItemId(item.item_id)))?; let real_trade_item = this.items .iter() @@ -367,69 +387,73 @@ pub async fn inner_items_to_trade(id: ClientId, this.status = TradeStatus::ItemsChecked; if this.status == TradeStatus::ItemsChecked && other.status == TradeStatus::ItemsChecked { - Ok(Box::new(vec![ + Ok(vec![ (this.client(), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {})), (other.client(), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {})), - ].into_iter()) as Box + Send>) + ]) } else { - Ok(Box::new(Vec::new().into_iter()) as Box + Send>) + Ok(Vec::new()) } }).await?; match pkts { Ok(pkts) => Ok(pkts), Err(err) => { log::warn!("trade error: {:?}", err); - let (_this, other) = trades.remove_trade(&id); - Ok(Box::new(client_location.get_all_clients_by_client(id).await?.into_iter() - .filter(move |client| other.as_ref().map(|other| client.client == other.client() ).unwrap_or_else(|| false)) - .map(move |client| { - (client.client, SendShipPacket::CancelTrade(CancelTrade {})) - }) - .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {})))))) + let (_this, other) = trades.remove_trade(&id).await; + Ok(client_location.get_all_clients_by_client(id).await?.into_iter() + .filter(move |client| other.as_ref().map(|other| client.client == other.client() ).unwrap_or_else(|| false)) + .map(move |client| { + (client.client, SendShipPacket::CancelTrade(CancelTrade {})) + }) + .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {})))) + .collect()) } } } pub async fn items_to_trade(id: ClientId, - items_to_trade_pkt: &ItemsToTrade, + items_to_trade_pkt: ItemsToTrade, client_location: &ClientLocation, - clients: &mut Clients, + clients: &Clients, item_state: &mut ItemState, trades: &mut TradeState) - -> Result + Send>, anyhow::Error> + -> Result, ShipError> { let t = inner_items_to_trade(id, items_to_trade_pkt, client_location, clients, item_state, trades).await; match t { Ok(p) => Ok(p), Err(err) => { log::warn!("atrade error: {:?}", err); - let (_this, other) = trades.remove_trade(&id); - Ok(Box::new(client_location.get_all_clients_by_client(id).await?.into_iter() - .filter(move |client| other.as_ref().map(|other| client.client == other.client()).unwrap_or_else(|| false)) - .map(move |client| { - (client.client, SendShipPacket::CancelTrade(CancelTrade {})) - }) - .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {})))))) + let (_this, other) = trades.remove_trade(&id).await; + Ok(client_location.get_all_clients_by_client(id).await?.into_iter() + .filter(move |client| other.as_ref().map(|other| client.client == other.client()).unwrap_or_else(|| false)) + .map(move |client| { + (client.client, SendShipPacket::CancelTrade(CancelTrade {})) + }) + .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {})))) + .collect()) } } } -pub async fn trade_confirmed_inner(id: ClientId, - mut entity_gateway: EG, +async fn trade_confirmed_inner(id: ClientId, + entity_gateway: &mut EG, client_location: &ClientLocation, - clients: &mut Clients, + clients: &Clients, item_state: &mut ItemState, trades: &mut TradeState) - -> Result + Send>, ShipError> + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static, { - enum TradeReady<'a> { + enum TradeReady/*<'a>*/ { OnePlayer, BothPlayers(RoomId, - (AreaClient, &'a crate::ship::ship::ClientState, crate::ship::trade::ClientTradeState), - (AreaClient, &'a crate::ship::ship::ClientState, crate::ship::trade::ClientTradeState)), + (AreaClient, crate::ship::trade::ClientTradeState), + (AreaClient, crate::ship::trade::ClientTradeState)), + //(AreaClient, &'a crate::ship::ship::ClientState, crate::ship::trade::ClientTradeState), + //(AreaClient, &'a crate::ship::ship::ClientState, crate::ship::trade::ClientTradeState)), } let trade = trades @@ -441,15 +465,13 @@ where this.status = TradeStatus::TradeComplete; if this.status == TradeStatus::TradeComplete && other.status == TradeStatus::TradeComplete { - let this_client = clients.get(&this.client()).ok_or_else(|| ShipError::ClientNotFound(this.client()))?; - let other_client = clients.get(&other.client()).ok_or_else(|| ShipError::ClientNotFound(other.client()))?; let this_local_client = client_location.get_local_client(this.client()).await?; let other_local_client = client_location.get_local_client(other.client()).await?; let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; Ok(TradeReady::BothPlayers(room_id, - (this_local_client, this_client, this.clone()), - (other_local_client, other_client, other.clone()))) + (this_local_client, /*this_client, */this.clone()), + (other_local_client, /*other_client, */other.clone()))) } else { Ok(TradeReady::OnePlayer) @@ -459,9 +481,9 @@ where match trade { TradeReady::OnePlayer => { - Ok(Box::new(None.into_iter()) as Box + Send>) + Ok(Vec::new()) }, - TradeReady::BothPlayers(_room_id, (this_local_client, this_client, this), (other_local_client, other_client, other)) => { + TradeReady::BothPlayers(_room_id, (this_local_client, /*this_client,*/ this), (other_local_client, /*other_client,*/ other)) => { let remove_item_packets = this.items .clone() .into_iter() @@ -478,11 +500,20 @@ where GameMessage::PlayerNoLongerHasItem(builder::message::player_no_longer_has_item(client, item.item_id(), item.amount() as u32)) }); - let (this_new_items, other_new_items) = trade_items(item_state, - &mut entity_gateway, - (&this_local_client, &this_client.character, &this.items, Meseta(this.meseta as u32)), - (&other_local_client, &other_client.character, &other.items, Meseta(other.meseta as u32))).await?; - + let this_items = this.items.clone(); + let other_items = other.items.clone(); + let (this_new_items, other_new_items) = clients.with_many( + [this_local_client.client, other_local_client.client], + |[this_client, other_client]| { + let mut entity_gateway = entity_gateway.clone(); + let mut item_state = item_state.clone(); + Box::pin(async move { + trade_items(&mut item_state, + &mut entity_gateway, + (&this_local_client, &this_client.character, &this_items, Meseta(this.meseta as u32)), + (&other_local_client, &other_client.character, &other_items, Meseta(other.meseta as u32))).await + })}).await??; + let create_item_packets = this_new_items .into_iter() .map(move |item| { @@ -541,32 +572,33 @@ where (this.client(), SendShipPacket::TradeSuccessful(TradeSuccessful::default())), (other.client(), SendShipPacket::TradeSuccessful(TradeSuccessful::default())) ].into_iter(); - Ok(Box::new(traded_item_packets.chain(close_trade))) + Ok(traded_item_packets.chain(close_trade).collect()) } } } pub async fn trade_confirmed(id: ClientId, - entity_gateway: EG, + entity_gateway: &mut EG, client_location: &ClientLocation, - clients: &mut Clients, + clients: &Clients, item_state: &mut ItemState, trades: &mut TradeState) - -> Result + Send>, ShipError> + -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + Clone + 'static, { match trade_confirmed_inner(id, entity_gateway, client_location, clients, item_state, trades).await { Ok(result) => Ok(result), Err(_err) => { - let (_this, other) = trades.remove_trade(&id); - Ok(Box::new(client_location.get_all_clients_by_client(id).await?.into_iter() - .filter(move |client| other.as_ref().map(|other| client.client == other.client()).unwrap_or_else(|| false)) - .map(move |client| { - (client.client, SendShipPacket::CancelTrade(CancelTrade {})) - }) - .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {})))))) + let (_this, other) = trades.remove_trade(&id).await; + Ok(client_location.get_all_clients_by_client(id).await?.into_iter() + .filter(move |client| other.as_ref().map(|other| client.client == other.client()).unwrap_or_else(|| false)) + .map(move |client| { + (client.client, SendShipPacket::CancelTrade(CancelTrade {})) + }) + .chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {})))) + .collect()) } } } diff --git a/src/ship/quests.rs b/src/ship/quests.rs index b326890..02c1906 100644 --- a/src/ship/quests.rs +++ b/src/ship/quests.rs @@ -4,6 +4,7 @@ use std::fs::File; use std::io::{Read, Write, Cursor, Seek, SeekFrom}; use std::path::PathBuf; use std::convert::TryInto; +use async_std::sync::Arc; use thiserror::Error; use serde::{Serialize, Deserialize}; use ages_prs::{LegacyPrsDecoder, LegacyPrsEncoder}; @@ -76,7 +77,7 @@ fn read_dat_section_header(cursor: &mut T, episode: &Episode, ma cursor.read_exact(&mut obj_data)?; let mut obj_cursor = Cursor::new(obj_data); - let objects = objects_from_stream(&mut obj_cursor, episode, map_area); + let objects = objects_from_stream(&mut obj_cursor, episode, &map_area); Ok(DatBlock::Object(objects)) }, DAT_ENEMY_HEADER_ID => { @@ -84,7 +85,7 @@ fn read_dat_section_header(cursor: &mut T, episode: &Episode, ma cursor.read_exact(&mut enemy_data)?; let mut enemy_cursor = Cursor::new(enemy_data); - let enemies = enemy_data_from_stream(&mut enemy_cursor, map_area, episode); + let enemies = enemy_data_from_stream(&mut enemy_cursor, &map_area, episode); Ok(DatBlock::Enemy(enemies)) }, @@ -159,18 +160,18 @@ pub enum QuestLoadError { CouldNotLoadConfigFile, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Quest { pub name: String, pub description: String, pub full_description: String, pub language: u16, pub id: u16, - pub bin_blob: Vec, - pub dat_blob: Vec, - pub enemies: Vec>, - pub objects: Vec>, - pub map_areas: MapAreaLookup, + pub bin_blob: Arc>, + pub dat_blob: Arc>, + pub enemies: Vec>, // TODO: Arc? + pub objects: Vec>, // TODO: Arc? + pub map_areas: MapAreaLookup, // TODO: Arc? } impl Quest { @@ -196,8 +197,8 @@ impl Quest { full_description, id, language, - bin_blob: prs_bin.into_inner().map_err(|_| QuestLoadError::CouldNotReadMetadata)?, - dat_blob: prs_dat.into_inner().map_err(|_| QuestLoadError::CouldNotReadMetadata)?, + bin_blob: Arc::new(prs_bin.into_inner().map_err(|_| QuestLoadError::CouldNotReadMetadata)?), + dat_blob: Arc::new(prs_dat.into_inner().map_err(|_| QuestLoadError::CouldNotReadMetadata)?), enemies, objects, map_areas, @@ -232,7 +233,7 @@ pub fn load_quest(bin_path: PathBuf, dat_path: PathBuf, quest_path: PathBuf) -> } -pub fn load_quests(quest_path: &mut PathBuf) -> Result { +pub fn load_quests(mut quest_path: PathBuf) -> Result { let mut f = File::open(quest_path.clone()).map_err(|_| QuestLoadError::CouldNotLoadConfigFile)?; let mut s = String::new(); f.read_to_string(&mut s)?; @@ -270,7 +271,7 @@ pub fn load_quests(quest_path: &mut PathBuf) -> Result>>; MAX_ROOMS]); + +impl Default for Rooms { + fn default() -> Rooms { + Rooms(core::array::from_fn(|_| Arc::new(RwLock::new(None)))) + } +} + + +/* +#[derive(escher::Rebindable)] +struct BorrowedRoom<'a> { + lock: RwLockReadGuard<'a, Option>, + room: &'a Option, +} + +impl<'a> std::ops::Deref for BorrowedRoom<'a> { + type Target = RoomState; + fn deref(&self) -> &Self::Target { + &self.room + } +} +*/ + + +impl Rooms { + pub async fn add(&self, room_id: RoomId, room: RoomState) -> Result<(), ShipError> { + *self.0 + .get(room_id.0) + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? + .write() + .await = Some(room); + Ok(()) + } + + pub async fn remove(&self, room_id: RoomId) { + if let Some(room) = self.0.get(room_id.0) { + *room + .write() + .await = None; + } + } + + pub async fn exists(&self, room_id: RoomId) -> bool { + match self.0.get(room_id.0) { + Some(room) => { + room + .read() + .await + .is_some() + }, + None => false, + } + } + + pub async fn with<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result + where + T: Send, + F: for<'b> FnOnce(&'b RoomState) -> BoxFuture<'b, T> + Send + 'a + { + let room = self.0 + .get(room_id.0) + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? + .read() + .await; + if let Some(room) = room.as_ref() { + Ok(func(room).await) + } + else { + Err(ShipError::InvalidRoom(room_id.0 as u32)) + } + } + + pub async fn with_mut<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result + where + T: Send, + F: for<'b> FnOnce(&'b mut RoomState) -> BoxFuture<'b, T> + Send + 'a + { + let mut room = self.0 + .get(room_id.0) + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? + .write() + .await; + + if let Some(room) = room.as_mut() { + Ok(func(room).await) + } + else { + Err(ShipError::InvalidRoom(room_id.0 as u32)) + } + } + + pub async fn get<'a>(&'a self, room_id: RoomId) -> RwLockReadGuard<'a, Option> { + self.0 + .get(room_id.0) + .unwrap() + .read() + .await + } + + pub fn stream<'a>(&'a self) -> impl Stream>> + 'a { + self.0 + .iter() + .map(|room| async move { + room + .read() + .await + }) + .collect::>() + } +} + + + + #[derive(Debug, Error)] @@ -279,7 +406,7 @@ impl RoomState { qpath.push(room_mode.to_string()); qpath.push("quests.toml"); let mut room_quests = Vec::new(); - let quest_list = match quests::load_quests(&mut qpath) { + let quest_list = match quests::load_quests(qpath) { Ok(qlist) => qlist, Err(_) => return Err(RoomCreationError::CouldNotLoadQuests), }; @@ -292,7 +419,7 @@ impl RoomState { qpath.push(room_mode.episode().to_string()); qpath.push("government/quests.toml"); - let quest_list = match quests::load_quests(&mut qpath) { + let quest_list = match quests::load_quests(qpath) { Ok(qlist) => qlist, Err(_) => return Err(RoomCreationError::CouldNotLoadQuests), }; diff --git a/src/ship/ship.rs b/src/ship/ship.rs index f744bc0..18ab8b2 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -2,6 +2,9 @@ use std::net::Ipv4Addr; use std::collections::HashMap; +use async_std::channel; +use async_std::sync::{Arc, Mutex}; + use rand::Rng; use thiserror::Error; @@ -13,6 +16,7 @@ use libpso::crypto::bb::PSOBBCipher; use libpso::packet::ship::{BLOCK_MENU_ID, ROOM_MENU_ID}; + use crate::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; use crate::common::interserver::{AuthToken, Ship, ServerId, InterserverActor, LoginMessage, ShipMessage}; @@ -24,7 +28,7 @@ use crate::entity::account::{UserAccountEntity, UserSettingsEntity}; use crate::entity::character::{CharacterEntity, SectionID}; use crate::entity::item; -use crate::ship::location::{ClientLocation, RoomLobby, MAX_ROOMS, ClientLocationError, GetNeighborError, GetClientsError, GetAreaError}; +use crate::ship::location::{ClientLocation, RoomLobby, MAX_ROOMS, ClientLocationError, GetNeighborError, GetClientsError, GetAreaError, RoomId}; use crate::ship::items; use crate::ship::room; @@ -33,11 +37,13 @@ use crate::ship::packet::handler; use crate::ship::shops::{WeaponShop, ToolShop, ArmorShop, WeaponShopItem, ToolShopItem, ArmorShopItem}; use crate::ship::trade::TradeState; +// TODO: remove once stuff settles down +pub use crate::ship::client::*; + pub const SHIP_PORT: u16 = 23423; pub const QUEST_CATEGORY_MENU_ID: u32 = 0xA2; pub const QUEST_SELECT_MENU_ID: u32 = 0xA3; -pub type Rooms = [Option; MAX_ROOMS]; -pub type Clients = HashMap; + #[derive(Error, Debug)] pub enum ShipError { @@ -50,13 +56,16 @@ pub enum ShipError { #[error("too many clients")] TooManyClients, #[error("client error location {0}")] - ClientLocationError(#[from] ClientLocationError), + //ClientLocationError(#[from] ClientLocationError), + ClientLocationError(ClientLocationError), + /* #[error("get neighbor error {0}")] GetNeighborError(#[from] GetNeighborError), #[error("get clients error {0}")] GetClientsError(#[from] GetClientsError), #[error("get area error {0}")] GetAreaError(#[from] GetAreaError), + */ #[error("maps error {0}")] MapsError(#[from] MapsError), #[error("map area error {0}")] @@ -105,8 +114,35 @@ pub enum ShipError { TradeError(#[from] crate::ship::packet::handler::trade::TradeError), #[error("trade state error {0}")] TradeStateError(#[from] crate::ship::trade::TradeStateError), + #[error("message error {0}")] + MessageError(#[from] crate::ship::packet::handler::direct_message::MessageError), + #[error("room creation error {0}")] + RoomCreationError(#[from] room::RoomCreationError), } +/* +impl From for ShipError { + fn from(other: &ClientLocationError) -> ShipError { + + } +} + */ + +/* +impl> Into for I { + fn into(other: I) -> ShipError { + ShipError::ClientLocationError(other.into()) + } +} + */ + +impl> From for ShipError { + fn from(other: I) -> ShipError { + ShipError::ClientLocationError(other.into()) + } +} + + #[derive(Debug)] pub enum RecvShipPacket { Login(Login), @@ -275,79 +311,11 @@ impl SendServerPacket for SendShipPacket { } } -#[derive(Debug, Clone, Copy)] -pub struct ItemDropLocation { - pub map_area: MapArea, - pub x: f32, - pub z: f32, - pub item_id: items::ClientItemId, -} - -pub struct LoadingQuest { - pub header_bin: Option, - pub header_dat: Option, - //pub quest_chunk_bin: Option>>, -} - - - -pub struct ClientState { - pub user: UserAccountEntity, - pub settings: UserSettingsEntity, - pub character: CharacterEntity, - session: Session, - //guildcard: GuildCard, - pub block: usize, - pub item_drop_location: Option, - pub done_loading_quest: bool, - //pub loading_quest: Option, - pub area: Option, - pub x: f32, - pub y: f32, - pub z: f32, - pub weapon_shop: Vec, - pub tool_shop: Vec, - pub armor_shop: Vec, - pub tek: Option<(items::ClientItemId, item::weapon::TekSpecialModifier, item::weapon::TekPercentModifier, i32)>, - pub character_playtime: chrono::Duration, - pub log_on_time: chrono::DateTime, -} - -impl ClientState { - pub fn new(user: UserAccountEntity, settings: UserSettingsEntity, character: CharacterEntity, session: Session) -> ClientState { - let character_playtime = chrono::Duration::seconds(character.playtime as i64); - ClientState { - user, - settings, - character, - session, - block: 0, - item_drop_location: None, - done_loading_quest: false, - area: None, - x: 0.0, - y: 0.0, - z: 0.0, - weapon_shop: Vec::new(), - tool_shop: Vec::new(), - armor_shop: Vec::new(), - tek: None, - character_playtime, - log_on_time: chrono::Utc::now(), - } - } - - fn update_playtime(&mut self) { - let additional_playtime = chrono::Utc::now() - self.log_on_time; - self.character.playtime = (self.character_playtime + additional_playtime).num_seconds() as u32; - } -} - - +#[derive(Clone)] pub struct ItemShops { - pub weapon_shop: HashMap<(room::Difficulty, SectionID), WeaponShop>, - pub tool_shop: ToolShop, - pub armor_shop: ArmorShop, + pub weapon_shop: HashMap<(room::Difficulty, SectionID), Arc>>>, + pub tool_shop: Arc>>, + pub armor_shop: Arc>>, } impl Default for ItemShops { @@ -359,20 +327,20 @@ impl Default for ItemShops { let mut weapon_shop = HashMap::new(); for d in difficulty.iter() { for id in section_id.iter() { - weapon_shop.insert((*d, *id), WeaponShop::new(*d, *id)); + weapon_shop.insert((*d, *id), Arc::new(Mutex::new(WeaponShop::new(*d, *id)))); } } ItemShops { weapon_shop, - tool_shop: ToolShop::default(), - armor_shop: ArmorShop::default(), + tool_shop: Arc::new(Mutex::new(ToolShop::default())), + armor_shop: Arc::new(Mutex::new(ArmorShop::default())), } } } -pub struct ShipServerStateBuilder { +pub struct ShipServerStateBuilder { entity_gateway: Option, name: Option, ip: Option, @@ -381,7 +349,7 @@ pub struct ShipServerStateBuilder { num_blocks: usize, } -impl Default for ShipServerStateBuilder { +impl Default for ShipServerStateBuilder { fn default() -> ShipServerStateBuilder { ShipServerStateBuilder { entity_gateway: None, @@ -394,7 +362,7 @@ impl Default for ShipServerStateBuilder { } } -impl ShipServerStateBuilder { +impl ShipServerStateBuilder { #[must_use] pub fn gateway(mut self, entity_gateway: EG) -> ShipServerStateBuilder { self.entity_gateway = Some(entity_gateway); @@ -435,12 +403,12 @@ impl ShipServerStateBuilder { let blocks = std::iter::repeat_with(Block::default).take(self.num_blocks).collect(); // Block doesn't have a Clone impl which limits the easy ways to init this ShipServerState { entity_gateway: self.entity_gateway.unwrap(), - clients: HashMap::new(), + clients: Clients::default(), name: self.name.unwrap_or_else(|| "NAMENOTSET".into()), item_state: items::state::ItemState::default(), ip: self.ip.unwrap_or_else(|| Ipv4Addr::new(127,0,0,1)), port: self.port.unwrap_or(SHIP_PORT), - shops: Box::new(ItemShops::default()), + shops: ItemShops::default(), blocks: Blocks(blocks), auth_token: self.auth_token.unwrap_or_else(|| AuthToken("".into())), @@ -451,37 +419,57 @@ impl ShipServerStateBuilder { } } + +#[derive(Clone)] pub struct Block { - client_location: Box, - pub rooms: Box, + client_location: ClientLocation, + pub rooms: room::Rooms, } impl Default for Block { fn default() -> Block { - const SNONE: Option = None; - const NONE: Rooms = [SNONE; MAX_ROOMS]; Block { - client_location: Box::new(ClientLocation::default()), - rooms: Box::new(NONE), + client_location: ClientLocation::default(), + rooms: room::Rooms::default(), + //rooms: core::array::from_fn(|_| Arc::new(RwLock::new(None))), } } } +/* +impl Block { + fn with(&self, func: F) -> T + where + T: Send, + F: FnOnce(&Block) -> T, + { + func(self) + } +} +*/ + +#[derive(Clone)] pub struct Blocks(pub Vec); impl Blocks { - fn with_client(&mut self, id: ClientId, clients: &Clients) -> Result<&mut Block, ShipError> { - let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - self.0.get_mut(client.block).ok_or(ShipError::InvalidBlock(client.block)) + async fn from_client(&mut self, id: ClientId, clients: &Clients) -> Result<&mut Block, ShipError> { + let block = clients.with(id, |client| Box::pin(async move { + client.block + })).await?; + self.0 + .get_mut(block) + .ok_or(ShipError::InvalidBlock(block)) } + } -pub struct ShipServerState { +#[derive(Clone)] +pub struct ShipServerState { entity_gateway: EG, pub clients: Clients, name: String, item_state: items::state::ItemState, - shops: Box, + shops: ItemShops, pub blocks: Blocks, ip: Ipv4Addr, @@ -489,127 +477,126 @@ pub struct ShipServerState { auth_token: AuthToken, ship_list: Vec, - shipgate_sender: Option>, + //shipgate_sender: Option>, + shipgate_sender: Option>, trades: TradeState, } -impl ShipServerState { +impl ShipServerState { pub fn builder() -> ShipServerStateBuilder { ShipServerStateBuilder::default() } - pub fn set_sender(&mut self, sender: Box) { - self.shipgate_sender = Some(sender); - } - - async fn message(&mut self, id: ClientId, msg: &Message) -> Result + Send>, anyhow::Error> { - Ok(match &msg.msg { + async fn message(&mut self, id: ClientId, msg: Message) -> Result, anyhow::Error> { + Ok(match msg.msg { GameMessage::RequestExp(request_exp) => { - let block = self.blocks.with_client(id, &self.clients)?; - handler::message::request_exp(id, request_exp, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut block.rooms).await? + let block = self.blocks.from_client(id, &self.clients).await?; + handler::message::request_exp(id, request_exp, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms).await? }, GameMessage::PlayerDropItem(player_drop_item) => { - let block = self.blocks.with_client(id, &self.clients)?; - handler::message::player_drop_item(id, player_drop_item, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_state).await? + let block = self.blocks.from_client(id, &self.clients).await?; + handler::message::player_drop_item(id, player_drop_item, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? }, GameMessage::DropCoordinates(drop_coordinates) => { - let block = self.blocks.with_client(id, &self.clients)?; + let block = self.blocks.from_client(id, &self.clients).await?; handler::message::drop_coordinates(id, drop_coordinates, &block.client_location, &mut self.clients, &block.rooms).await? }, GameMessage::PlayerNoLongerHasItem(no_longer_has_item) => { - let block = self.blocks.with_client(id, &self.clients)?; - handler::message::no_longer_has_item(id, no_longer_has_item, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state).await? + let block = self.blocks.from_client(id, &self.clients).await?; + handler::message::no_longer_has_item(id, no_longer_has_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? }, GameMessage::PlayerChangedMap(_) | GameMessage::PlayerChangedMap2(_) | GameMessage::TellOtherPlayerMyLocation(_) | GameMessage::PlayerWarpingToFloor(_) | GameMessage::PlayerTeleported(_) | GameMessage::PlayerStopped(_) | GameMessage::PlayerLoadedIn(_) | GameMessage::PlayerWalking(_) | GameMessage::PlayerRunning(_) | GameMessage::PlayerWarped(_) | GameMessage::PlayerChangedFloor(_) | GameMessage::InitializeSpeechNpc(_) => { - let block = self.blocks.with_client(id, &self.clients)?; + let block = self.blocks.from_client(id, &self.clients).await?; handler::message::update_player_position(id, msg, &mut self.clients, &block.client_location, &block.rooms).await? }, GameMessage::ChargeAttack(charge_attack) => { - let block = self.blocks.with_client(id, &self.clients)?; - handler::message::charge_attack(id, charge_attack, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state).await? + let block = self.blocks.from_client(id, &self.clients).await?; + handler::message::charge_attack(id, charge_attack, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? }, GameMessage::PlayerUseItem(player_use_item) => { - let block = self.blocks.with_client(id, &self.clients)?; - handler::message::player_uses_item(id, player_use_item, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state).await? + let block = self.blocks.from_client(id, &self.clients).await?; + handler::message::player_uses_item(id, player_use_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? }, GameMessage::PlayerUsedMedicalCenter(player_used_medical_center) => { - let block = self.blocks.with_client(id, &self.clients)?; - handler::message::player_used_medical_center(id, player_used_medical_center, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state).await? + let block = self.blocks.from_client(id, &self.clients).await?; + handler::message::player_used_medical_center(id, player_used_medical_center, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? }, GameMessage::PlayerFeedMag(player_feed_mag) => { - let block = self.blocks.with_client(id, &self.clients)?; - handler::message::player_feed_mag(id, player_feed_mag, self.entity_gateway.clone(), &block.client_location, &self.clients, &mut self.item_state).await? + let block = self.blocks.from_client(id, &self.clients).await?; + handler::message::player_feed_mag(id, player_feed_mag, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerEquipItem(player_equip_item) => { - handler::message::player_equips_item(id, player_equip_item, self.entity_gateway.clone(), &self.clients, &mut self.item_state).await? + handler::message::player_equips_item(id, player_equip_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerUnequipItem(player_unequip_item) => { - handler::message::player_unequips_item(id, player_unequip_item, self.entity_gateway.clone(), &self.clients, &mut self.item_state).await? + handler::message::player_unequips_item(id, player_unequip_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? }, GameMessage::SortItems(sort_items) => { - handler::message::player_sorts_items(id, sort_items, self.entity_gateway.clone(), &self.clients, &mut self.item_state).await? + handler::message::player_sorts_items(id, sort_items, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerSoldItem(player_sold_item) => { - handler::message::player_sells_item(id, player_sold_item, self.entity_gateway.clone(), &mut self.clients, &mut self.item_state).await? + handler::message::player_sells_item(id, player_sold_item, &mut self.entity_gateway, &mut self.clients, &mut self.item_state).await? }, _ => { let cmsg = msg.clone(); - let block = self.blocks.with_client(id, &self.clients)?; - Box::new(block.client_location.get_client_neighbors(id).await.unwrap().into_iter() + let block = self.blocks.from_client(id, &self.clients).await?; + block.client_location.get_client_neighbors(id).await.unwrap().into_iter() .map(move |client| { (client.client, SendShipPacket::Message(cmsg.clone())) - })) + }) + .collect() }, }) } - async fn direct_message(&mut self, id: ClientId, msg: &DirectMessage) -> Result + Send>, anyhow::Error> { + async fn direct_message(&mut self, id: ClientId, msg: DirectMessage) -> Result, anyhow::Error> { let target = msg.flag; - let block = self.blocks.with_client(id, &self.clients)?; - Ok(match &msg.msg { + let block = self.blocks.from_client(id, &self.clients).await?; + Ok(match msg.msg { GameMessage::GuildcardSend(guildcard_send) => { - handler::direct_message::guildcard_send(id, guildcard_send, target, &block.client_location, &self.clients).await + handler::direct_message::guildcard_send(id, guildcard_send, target, &block.client_location, &self.clients).await? }, GameMessage::RequestItem(request_item) => { - handler::direct_message::request_item(id, request_item, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_state).await? + handler::direct_message::request_item(id, request_item, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? }, GameMessage::PickupItem(pickup_item) => { - handler::direct_message::pickup_item(id, pickup_item, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state).await? + handler::direct_message::pickup_item(id, pickup_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::BoxDropRequest(box_drop_request) => { - handler::direct_message::request_box_item(id, box_drop_request, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_state).await? + handler::direct_message::request_box_item(id, box_drop_request, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? }, GameMessage::BankRequest(_bank_request) => { handler::direct_message::send_bank_list(id, &self.clients, &mut self.item_state).await? }, GameMessage::BankInteraction(bank_interaction) => { - handler::direct_message::bank_interaction(id, bank_interaction, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state).await? + handler::direct_message::bank_interaction(id, bank_interaction, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::ShopRequest(shop_request) => { - handler::direct_message::shop_request(id, shop_request, &block.client_location, &mut self.clients, &block.rooms, &mut self.shops).await? + handler::direct_message::shop_request(id, shop_request, &block.client_location, &self.clients, &block.rooms, &mut self.shops).await? }, GameMessage::BuyItem(buy_item) => { - handler::direct_message::buy_item(id, buy_item, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state).await? + handler::direct_message::buy_item(id, buy_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::TekRequest(tek_request) => { - handler::direct_message::request_tek_item(id, tek_request, self.entity_gateway.clone(), &mut self.clients, &mut self.item_state).await? + handler::direct_message::request_tek_item(id, tek_request, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? }, GameMessage::TekAccept(tek_accept) => { - handler::direct_message::accept_tek_item(id, tek_accept, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state).await? + handler::direct_message::accept_tek_item(id, tek_accept, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::TradeRequest(trade_request) => { - handler::trade::trade_request(id, trade_request, target, &block.client_location, &mut self.clients, &mut self.item_state, &mut self.trades).await? + handler::trade::trade_request(id, trade_request, target, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? }, _ => { let cmsg = msg.clone(); - Box::new(block.client_location.get_all_clients_by_client(id).await.unwrap().into_iter() + block.client_location.get_all_clients_by_client(id).await.unwrap().into_iter() .filter(move |client| client.local_client.id() == target as u8) .map(move |client| { (client.client, SendShipPacket::DirectMessage(cmsg.clone())) - })) + }) + .collect() }, }) } @@ -619,9 +606,10 @@ impl ShipServerState { impl ServerState for ShipServerState { type SendPacket = SendShipPacket; type RecvPacket = RecvShipPacket; + type Cipher = PSOBBCipher; type PacketError = anyhow::Error; - async fn on_connect(&mut self, _id: ClientId) -> Result>, anyhow::Error> { + async fn on_connect(&mut self, _id: ClientId) -> Result>, anyhow::Error> { let mut rng = rand::thread_rng(); let mut server_key = [0u8; 48]; @@ -630,59 +618,104 @@ impl ServerState for ShipServerState { rng.fill(&mut client_key[..]); Ok(vec![OnConnect::Packet(SendShipPacket::ShipWelcome(ShipWelcome::new(server_key, client_key))), - OnConnect::Cipher((Box::new(PSOBBCipher::new(ELSEWHERE_PARRAY, ELSEWHERE_PRIVATE_KEY, client_key)), - Box::new(PSOBBCipher::new(ELSEWHERE_PARRAY, ELSEWHERE_PRIVATE_KEY, server_key)))) + OnConnect::Cipher(PSOBBCipher::new(ELSEWHERE_PARRAY, ELSEWHERE_PRIVATE_KEY, client_key), + PSOBBCipher::new(ELSEWHERE_PARRAY, ELSEWHERE_PRIVATE_KEY, server_key)) ]) } - async fn handle(&mut self, id: ClientId, pkt: &RecvShipPacket) - -> Result + Send>, anyhow::Error> { + async fn handle(&mut self, id: ClientId, pkt: RecvShipPacket) -> Result, anyhow::Error> { + if let Ok((char_id, char_playtime)) = self.clients.with_mut(id, |client| Box::pin(async move { + client.update_playtime(); + (client.character.id, client.character.playtime) + })).await { + self.entity_gateway.set_character_playtime(&char_id, char_playtime).await?; + } + /* if let Some(client) = self.clients.get_mut(&id) { client.update_playtime(); self.entity_gateway.set_character_playtime(&client.character.id, client.character.playtime).await?; - } + }*/ Ok(match pkt { RecvShipPacket::Login(login) => { - Box::new(handler::auth::validate_login(id, login, self.entity_gateway.clone(), &mut self.clients, &mut self.item_state, &self.shipgate_sender, &self.name, self.blocks.0.len()) - .await?.into_iter().map(move |pkt| (id, pkt))) + handler::auth::validate_login(id, login, &mut self.entity_gateway, &mut self.clients, &mut self.item_state, &self.shipgate_sender, &self.name, self.blocks.0.len()) + .await? + .into_iter() + .map(move |pkt| (id, pkt)) + .collect() }, RecvShipPacket::QuestDetailRequest(questdetailrequest) => { - let block = self.blocks.with_client(id, &self.clients)?; + let block = self.blocks.from_client(id, &self.clients).await?; match questdetailrequest.menu { QUEST_SELECT_MENU_ID => handler::quest::quest_detail(id, questdetailrequest, &block.client_location, &mut block.rooms).await?, _ => unreachable!(), } }, RecvShipPacket::MenuSelect(menuselect) => { - let block = self.blocks.with_client(id, &self.clients)?; + let block = self.blocks.from_client(id, &self.clients).await?; match menuselect.menu { SHIP_MENU_ID => { let leave_lobby = handler::lobby::remove_from_lobby(id, &mut block.client_location).await.into_iter().into_iter().flatten(); let select_ship = handler::ship::selected_ship(id, menuselect, &self.ship_list)?; - Box::new(leave_lobby.chain(select_ship)) + leave_lobby.chain(select_ship).collect() } BLOCK_MENU_ID => { let leave_lobby = handler::lobby::remove_from_lobby(id, &mut block.client_location).await.into_iter().into_iter().flatten(); - let select_block = handler::lobby::block_selected(id, menuselect, &mut self.clients, &self.item_state)?.into_iter(); - Box::new(leave_lobby.chain(select_block)) + let select_block = handler::lobby::block_selected(id, menuselect, &self.clients, &self.item_state).await?.into_iter(); + leave_lobby.chain(select_block).collect() } - ROOM_MENU_ID => handler::room::join_room(id, menuselect, &mut block.client_location, &mut self.clients, &mut self.item_state, &mut block.rooms).await?, + ROOM_MENU_ID => handler::room::join_room(id, menuselect, &mut block.client_location, &self.clients, &mut self.item_state, &mut block.rooms).await?, QUEST_CATEGORY_MENU_ID => handler::quest::select_quest_category(id, menuselect, &block.client_location, &mut block.rooms).await?, _ => unreachable!(), } }, RecvShipPacket::QuestMenuSelect(questmenuselect) => { - let block = self.blocks.with_client(id, &self.clients)?; + let block = self.blocks.from_client(id, &self.clients).await?; handler::quest::player_chose_quest(id, questmenuselect, &mut self.clients, &block.client_location, &mut block.rooms).await? }, RecvShipPacket::MenuDetail(menudetail) => { - let block = self.blocks.with_client(id, &self.clients)?; - Box::new(handler::lobby::get_room_tab_info(id, menudetail, &mut block.client_location, &self.clients, &mut block.rooms).await?.into_iter()) + let block = self.blocks.from_client(id, &self.clients).await?; + handler::lobby::get_room_tab_info(id, menudetail, &mut block.client_location, &self.clients, &mut block.rooms).await? }, RecvShipPacket::RoomPasswordReq(room_password_req) => { - let block = self.blocks.with_client(id, &self.clients)?; - if room_password_req.password == block.rooms[room_password_req.item as usize].as_ref() + let block = self.blocks.from_client(id, &self.clients).await?; + + /* + let password = room_password_req.password; + let correct_password = block.rooms.with(RoomId(room_password_req.item as usize), |room| Box::pin(async move { + password == room.password + })).await?; + */ + + let room_password = block.rooms.with(RoomId(room_password_req.item as usize), |room| Box::pin(async move { + room.password + })).await?; + + /* + let correct_password = room_password_req.password == block.rooms + .get(RoomId(room_password_req.item as usize)) + .await + .map(|room| room.password) + .unwrap_or_else(false); + */ + + //if correct_password { + if room_password_req.password == room_password { + let menuselect = MenuSelect { + menu: room_password_req.menu, + item: room_password_req.item, + }; + handler::room::join_room(id, menuselect, &mut block.client_location, &mut self.clients, &mut self.item_state, &mut block.rooms).await? + } + else { + vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Incorrect password".into())))] + } + + /* + if room_password_req.password == block.rooms[room_password_req.item as usize] + .read() + .await + .as_ref() .ok_or(ShipError::InvalidRoom(room_password_req.item))? .password { let menuselect = MenuSelect { @@ -694,10 +727,11 @@ impl ServerState for ShipServerState { else { Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Incorrect password".into())))].into_iter()) } + */ }, RecvShipPacket::CharData(chardata) => { - let block = self.blocks.with_client(id, &self.clients)?; - Box::new(handler::lobby::send_player_to_lobby(id, chardata, &mut block.client_location, &self.clients, &self.item_state).await?.into_iter()) + let block = self.blocks.from_client(id, &self.clients).await?; + handler::lobby::send_player_to_lobby(id, chardata, &mut block.client_location, &self.clients, &self.item_state).await? }, RecvShipPacket::Message(msg) => { self.message(id, msg).await? @@ -706,72 +740,72 @@ impl ServerState for ShipServerState { self.direct_message(id, msg).await? }, RecvShipPacket::PlayerChat(msg) => { - let block = self.blocks.with_client(id, &self.clients)?; - Box::new(handler::communication::player_chat(id, msg, &block.client_location, &self.clients).await?) + let block = self.blocks.from_client(id, &self.clients).await?; + handler::communication::player_chat(id, msg, &block.client_location, &self.clients).await? }, RecvShipPacket::CreateRoom(create_room) => { - let block = self.blocks.with_client(id, &self.clients)?; + let block = self.blocks.from_client(id, &self.clients).await?; handler::room::create_room(id, create_room, &mut block.client_location, &mut self.clients, &mut self.item_state, &mut block.rooms).await? }, RecvShipPacket::RoomNameRequest(_req) => { - let block = self.blocks.with_client(id, &self.clients)?; - handler::room::room_name_request(id, &block.client_location, &block.rooms).await + let block = self.blocks.from_client(id, &self.clients).await?; + handler::room::room_name_request(id, &block.client_location, &block.rooms).await? }, RecvShipPacket::UpdateConfig(pkt) => { - handler::settings::update_config(id, pkt, &mut self.clients, self.entity_gateway.clone()).await + handler::settings::update_config(id, pkt, &mut self.clients, &mut self.entity_gateway).await? }, RecvShipPacket::ViewInfoboardRequest(_pkt) => { - let block = self.blocks.with_client(id, &self.clients)?; - handler::communication::request_infoboard(id, &block.client_location, &self.clients).await + let block = self.blocks.from_client(id, &self.clients).await?; + handler::communication::request_infoboard(id, &block.client_location, &self.clients).await? }, RecvShipPacket::WriteInfoboard(pkt) => { - handler::communication::write_infoboard(id, pkt, &mut self.clients, self.entity_gateway.clone()).await + handler::communication::write_infoboard(id, pkt, &self.clients, &mut self.entity_gateway).await? }, RecvShipPacket::RoomListRequest(_req) => { - let block = self.blocks.with_client(id, &self.clients)?; + let block = self.blocks.from_client(id, &self.clients).await?; handler::room::request_room_list(id, &block.client_location, &block.rooms).await }, RecvShipPacket::Like62ButCooler(cool62) => { - let block = self.blocks.with_client(id, &self.clients)?; + let block = self.blocks.from_client(id, &self.clients).await?; handler::room::cool_62(id, cool62, &block.client_location).await }, RecvShipPacket::ClientCharacterData(_) => { // TOOD: validate this in some way? - Box::new(None.into_iter()) + Vec::new() }, RecvShipPacket::DoneBursting(_) => { - let block = self.blocks.with_client(id, &self.clients)?; - handler::room::done_bursting(id, &block.client_location, &mut block.rooms).await + let block = self.blocks.from_client(id, &self.clients).await?; + handler::room::done_bursting(id, &block.client_location, &mut block.rooms).await? }, RecvShipPacket::DoneBursting2(_) => { - let block = self.blocks.with_client(id, &self.clients)?; - handler::room::done_bursting(id, &block.client_location, &mut block.rooms).await + let block = self.blocks.from_client(id, &self.clients).await?; + handler::room::done_bursting(id, &block.client_location, &mut block.rooms).await? }, RecvShipPacket::LobbySelect(pkt) => { - let block = self.blocks.with_client(id, &self.clients)?; - Box::new(handler::lobby::change_lobby(id, pkt.lobby, &mut block.client_location, &self.clients, &mut self.item_state, &mut block.rooms, self.entity_gateway.clone()).await?.into_iter()) + let block = self.blocks.from_client(id, &self.clients).await?; + handler::lobby::change_lobby(id, pkt.lobby, &mut block.client_location, &self.clients, &mut self.item_state, &mut block.rooms, &mut self.entity_gateway).await? }, RecvShipPacket::RequestQuestList(rql) => { - let block = self.blocks.with_client(id, &self.clients)?; + let block = self.blocks.from_client(id, &self.clients).await?; handler::quest::send_quest_category_list(id, rql, &block.client_location, &mut block.rooms).await? }, RecvShipPacket::QuestFileRequest(quest_file_request) => { - let block = self.blocks.with_client(id, &self.clients)?; + let block = self.blocks.from_client(id, &self.clients).await?; handler::quest::quest_file_request(id, quest_file_request, &block.client_location, &mut block.rooms).await? }, RecvShipPacket::QuestChunkAck(quest_chunk_ack) => { - let block = self.blocks.with_client(id, &self.clients)?; + let block = self.blocks.from_client(id, &self.clients).await?; handler::quest::quest_chunk_ack(id, quest_chunk_ack, &block.client_location, &mut block.rooms).await? }, RecvShipPacket::DoneLoadingQuest(_) => { - let block = self.blocks.with_client(id, &self.clients)?; - handler::quest::done_loading_quest(id, &mut self.clients, &block.client_location).await? + let block = self.blocks.from_client(id, &self.clients).await?; + handler::quest::done_loading_quest(id, &self.clients, &block.client_location).await? }, RecvShipPacket::FullCharacterData(_full_character_data) => { - Box::new(None.into_iter()) + Vec::new() }, RecvShipPacket::SaveOptions(save_options) => { - handler::settings::save_options(id, save_options, &mut self.clients, self.entity_gateway.clone()).await + handler::settings::save_options(id, save_options, &self.clients, &mut self.entity_gateway).await? }, RecvShipPacket::RequestShipList(_) => { handler::ship::ship_list(id, &self.ship_list) @@ -780,32 +814,32 @@ impl ServerState for ShipServerState { handler::ship::block_list(id, &self.name, self.blocks.0.len()) }, RecvShipPacket::ItemsToTrade(items_to_trade) => { - let block = self.blocks.with_client(id, &self.clients)?; - handler::trade::items_to_trade(id, items_to_trade, &block.client_location, &mut self.clients, &mut self.item_state, &mut self.trades).await? + let block = self.blocks.from_client(id, &self.clients).await?; + handler::trade::items_to_trade(id, items_to_trade, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? }, RecvShipPacket::TradeConfirmed(_) => { - let block = self.blocks.with_client(id, &self.clients)?; - handler::trade::trade_confirmed(id, self.entity_gateway.clone(), &block.client_location, &mut self.clients, &mut self.item_state, &mut self.trades).await? + let block = self.blocks.from_client(id, &self.clients).await?; + handler::trade::trade_confirmed(id, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? }, RecvShipPacket::KeyboardConfig(keyboard_config) => { - handler::settings::keyboard_config(id, keyboard_config, &mut self.clients, self.entity_gateway.clone()).await + handler::settings::keyboard_config(id, keyboard_config, &self.clients, &mut self.entity_gateway).await? }, RecvShipPacket::GamepadConfig(gamepad_config) => { - handler::settings::gamepad_config(id, gamepad_config, &mut self.clients, self.entity_gateway.clone()).await + handler::settings::gamepad_config(id, gamepad_config, &self.clients, &mut self.entity_gateway).await? }, }) } async fn on_disconnect(&mut self, id: ClientId) -> Result, anyhow::Error> { - let client = self.clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - let block = self.blocks.with_client(id, &self.clients)?; + //let client = self.clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; + let block = self.blocks.from_client(id, &self.clients).await?; let area_client = block.client_location.get_local_client(id).await?; let neighbors = block.client_location.get_client_neighbors(id).await?; let pkt = match block.client_location.get_area(id).await? { RoomLobby::Room(room) => { if neighbors.is_empty() { - block.rooms[room.0] = None; + block.rooms.remove(room).await; } let leader = block.client_location.get_room_leader(room).await?; SendShipPacket::LeaveRoom(LeaveRoom::new(area_client.local_client.id(), leader.local_client.id())) @@ -816,16 +850,24 @@ impl ServerState for ShipServerState { } }; + /* if let Some(shipgate_sender) = self.shipgate_sender.as_ref() { - shipgate_sender(ShipMessage::RemoveUser(client.user.id)); + shipgate_sender.send(ShipMessage::RemoveUser(client.user.id)).await; } block.client_location.remove_client_from_area(id).await; - self.item_state.remove_character_from_room(&client.character); + self.clients.with(id, |client| Box::pin(async move { + self.item_state.remove_character_from_room(&client.character).await + })).await?; + */ - if let Some(mut client) = self.clients.remove(&id) { + if let Some(mut client) = self.clients.remove(&id).await { client.user.at_ship = false; self.entity_gateway.save_user(&client.user).await; + if let Some(shipgate_sender) = self.shipgate_sender.as_ref() { + shipgate_sender.send(ShipMessage::RemoveUser(client.user.id)).await; + } + self.item_state.remove_character_from_room(&client.character).await } Ok(neighbors.into_iter().map(|n| { @@ -854,7 +896,7 @@ impl InterserverActor for ShipServerState { ] } - async fn action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result, Self::Error> { + async fn on_action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result, Self::Error> { match msg { LoginMessage::SendMail{..} => { Ok(Vec::new()) @@ -864,11 +906,15 @@ impl InterserverActor for ShipServerState { Ok(Vec::new()) }, LoginMessage::RequestUsers => { + /* Ok(self.clients.iter() .map(|(_, client)| { (id, ShipMessage::AddUser(client.user.id)) }) .collect()) + */ + // TODO + Ok(Vec::new()) } } } @@ -876,4 +922,8 @@ impl InterserverActor for ShipServerState { async fn on_disconnect(&mut self, _id: ServerId) -> Vec<(ServerId, Self::SendMessage)> { Vec::new() } + + fn set_sender(&mut self, _server_id: ServerId, sender: channel::Sender) { + self.shipgate_sender = Some(sender); + } } diff --git a/src/ship/trade.rs b/src/ship/trade.rs index 790c354..abe1cd2 100644 --- a/src/ship/trade.rs +++ b/src/ship/trade.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; use crate::common::serverstate::ClientId; use crate::ship::items; -use async_std::sync::{Mutex, MutexGuard}; -use futures::future::Future; +use async_std::sync::{Arc, Mutex, MutexGuard}; +use futures::future::{Future, OptionFuture}; #[derive(Debug, Clone)] pub enum TradeItem { @@ -81,9 +81,9 @@ pub enum TradeStateError { MismatchedTrade(ClientId, ClientId), } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct TradeState { - trades: HashMap>, + trades: HashMap>>, } impl TradeState { @@ -95,7 +95,7 @@ impl TradeState { meseta: 0, status: TradeStatus::SentRequest, }; - self.trades.insert(*sender, Mutex::new(state)); + self.trades.insert(*sender, Arc::new(Mutex::new(state))); let state = ClientTradeState { client: *receiver, @@ -104,13 +104,14 @@ impl TradeState { meseta: 0, status: TradeStatus::ReceivedRequest, }; - self.trades.insert(*receiver, Mutex::new(state)); + self.trades.insert(*receiver, Arc::new(Mutex::new(state))); } pub fn in_trade(&self, client: &ClientId) -> bool { self.trades.contains_key(client) } + /* pub async fn with<'a, T, F, Fut> (&'a self, client: &ClientId, func: F) -> Result where F: FnOnce(MutexGuard<'a, ClientTradeState>, MutexGuard<'a, ClientTradeState>) -> Fut + 'a, @@ -125,12 +126,38 @@ impl TradeState { } Ok(func(c1, c2).await) } + */ + pub async fn with<'a, T, F, Fut> (&'a self, client: &ClientId, func: F) -> Result + where + T: Send, + //F: for<'b> FnOnce(&'b mut ClientTradeState, &'b mut ClientTradeState) -> BoxFuture<'b, T> + Send + 'a + //F: for<'b> FnOnce(&'b mut ClientTradeState, &'b mut ClientTradeState) -> Fut + Send + 'a, + F: FnOnce(MutexGuard<'a, ClientTradeState>, MutexGuard<'a, ClientTradeState>) -> Fut + 'a, + Fut: Future, + { + let c1 = self.trades + .get(client) + .ok_or(TradeStateError::ClientNotInTrade(*client))? + .lock() + .await; + let c2 = self.trades + .get(&c1.other_client) + .ok_or(TradeStateError::ClientNotInTrade(c1.other_client))? + .lock() + .await; + + if c1.client != c2.other_client { + return Err(TradeStateError::MismatchedTrade(c1.client, c2.client)); + } + + Ok(func(c1, c2).await) + } // TODO: is it possible for this to not return Options? - pub fn remove_trade(&mut self, client: &ClientId) -> (Option, Option) { - let c1 = self.trades.remove(client).map(|c| c.into_inner()); + pub async fn remove_trade(&mut self, client: &ClientId) -> (Option, Option) { + let c1 = OptionFuture::from(self.trades.remove(client).map(|c| async move {c.lock().await.clone()} )).await; let c2 = if let Some(ref state) = c1 { - self.trades.remove(&state.other_client).map(|c| c.into_inner()) + OptionFuture::from(self.trades.remove(&state.other_client).map(|c| async move {c.lock().await.clone()})).await } else { None diff --git a/tests/common.rs b/tests/common.rs index 0243945..d2ea567 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -37,7 +37,7 @@ pub async fn new_user_character(entity_gateway: &mut pub async fn log_in_char(ship: &mut ShipServerState, id: ClientId, username: &str, password: &str) { let username = username.to_string(); let password = password.to_string(); - ship.handle(id, &RecvShipPacket::Login(Login { + ship.handle(id, RecvShipPacket::Login(Login { tag: 0, guildcard: 0, version: 0, @@ -49,13 +49,13 @@ pub async fn log_in_char(ship: &mut ShipServerState(ship: &mut ShipServerState, id: ClientId) { - ship.handle(id, &RecvShipPacket::CharData(CharData { + ship.handle(id, RecvShipPacket::CharData(CharData { _unknown: [0; 0x828] - })).await.unwrap().for_each(drop); + })).await.unwrap(); } pub async fn create_room(ship: &mut ShipServerState, id: ClientId, name: &str, password: &str) { @@ -63,14 +63,14 @@ pub async fn create_room(ship: &mut ShipServerState(ship: &mut ShipServerState, id: ClientId) { - ship.handle(id, &RecvShipPacket::LobbySelect(LobbySelect { + ship.handle(id, RecvShipPacket::LobbySelect(LobbySelect { menu: 3, lobby: 0, - })).await.unwrap().for_each(drop); + })).await.unwrap(); } pub async fn create_room_with_difficulty(ship: &mut ShipServerState, id: ClientId, name: &str, password: &str, difficulty: Difficulty) { - ship.handle(id, &RecvShipPacket::CreateRoom(CreateRoom { + ship.handle(id, RecvShipPacket::CreateRoom(CreateRoom { unknown: [0; 2], name: utf8_to_utf16_array!(name, 16), password: utf8_to_utf16_array!(password, 16), @@ -80,14 +80,14 @@ pub async fn create_room_with_difficulty(ship: &mut S episode: 1, single_player: 0, padding: [0; 3], - })).await.unwrap().for_each(drop); - ship.handle(id, &RecvShipPacket::DoneBursting(DoneBursting {})).await.unwrap().for_each(drop); + })).await.unwrap(); + ship.handle(id, RecvShipPacket::DoneBursting(DoneBursting {})).await.unwrap(); } pub async fn join_room(ship: &mut ShipServerState, id: ClientId, room_id: u32) { - ship.handle(id, &RecvShipPacket::MenuSelect(MenuSelect { + ship.handle(id, RecvShipPacket::MenuSelect(MenuSelect { menu: ROOM_MENU_ID, item: room_id, - })).await.unwrap().for_each(drop); - ship.handle(id, &RecvShipPacket::DoneBursting(DoneBursting {})).await.unwrap().for_each(drop); + })).await.unwrap(); + ship.handle(id, RecvShipPacket::DoneBursting(DoneBursting {})).await.unwrap(); } diff --git a/tests/test_bank.rs b/tests/test_bank.rs index 43a4364..e809371 100644 --- a/tests/test_bank.rs +++ b/tests/test_bank.rs @@ -38,10 +38,10 @@ async fn test_bank_items_sent_in_character_login() { .build()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; - let packets = ship.handle(ClientId(1), &RecvShipPacket::MenuSelect(MenuSelect { + let packets = ship.handle(ClientId(1), RecvShipPacket::MenuSelect(MenuSelect { menu: BLOCK_MENU_ID, item: 1, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert!(matches!(&packets[0], (_, SendShipPacket::FullCharacter(fc)) if fc.character.bank.items[0].data1[0..3] == [0x00, 0x08, 0x04] )); } @@ -78,11 +78,11 @@ async fn test_request_bank_items() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert!(matches!(&packets[0], (_, SendShipPacket::BankItemList (bank_item_list)) if bank_item_list.item_count == 3 @@ -122,11 +122,11 @@ async fn test_request_stacked_bank_items() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert!(matches!(&packets[0], (_, SendShipPacket::BankItemList (bank_item_list)) if bank_item_list.item_count == 1 @@ -187,11 +187,11 @@ async fn test_request_bank_items_sorted() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert!(matches!(&packets[0], (_, SendShipPacket::BankItemList (bank_item_list)) if bank_item_list.item_count == 3 @@ -247,13 +247,13 @@ async fn test_deposit_individual_item() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0x10001, @@ -261,7 +261,7 @@ async fn test_deposit_individual_item() { item_amount: 0, meseta_amount: 0, unknown: 0, - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert!(packets.len() == 2); assert!(matches!(&packets[1], (ClientId(2), SendShipPacket::Message(Message {msg: GameMessage::PlayerNoLongerHasItem(player_no_longer_has_item)})) @@ -313,13 +313,13 @@ async fn test_deposit_stacked_item() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0x10000, @@ -327,7 +327,7 @@ async fn test_deposit_stacked_item() { item_amount: 3, meseta_amount: 0, unknown: 0, - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert!(packets.len() == 2); assert!(matches!(&packets[1], (ClientId(2), SendShipPacket::Message(Message {msg: GameMessage::PlayerNoLongerHasItem(player_no_longer_has_item)})) @@ -374,13 +374,13 @@ async fn test_deposit_partial_stacked_item() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0x10000, @@ -388,7 +388,7 @@ async fn test_deposit_partial_stacked_item() { item_amount: 2, meseta_amount: 0, unknown: 0, - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert!(packets.len() == 2); assert!(matches!(&packets[1], (ClientId(2), SendShipPacket::Message(Message {msg: GameMessage::PlayerNoLongerHasItem(player_no_longer_has_item)})) @@ -455,13 +455,13 @@ async fn test_deposit_stacked_item_with_stack_already_in_bank() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0x10000, @@ -469,7 +469,7 @@ async fn test_deposit_stacked_item_with_stack_already_in_bank() { item_amount: 2, meseta_amount: 0, unknown: 0, - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert!(packets.len() == 2); assert!(matches!(&packets[1], (ClientId(2), SendShipPacket::Message(Message {msg: GameMessage::PlayerNoLongerHasItem(player_no_longer_has_item)})) @@ -525,13 +525,13 @@ async fn test_deposit_stacked_item_with_full_stack_in_bank() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0x10000, @@ -603,13 +603,13 @@ async fn test_deposit_individual_item_in_full_bank() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0x10000, @@ -675,13 +675,13 @@ async fn test_deposit_stacked_item_in_full_bank() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0x10000, @@ -761,13 +761,13 @@ async fn test_deposit_stacked_item_in_full_bank_with_partial_stack() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0x10000, @@ -775,7 +775,7 @@ async fn test_deposit_stacked_item_in_full_bank_with_partial_stack() { item_amount: 2, meseta_amount: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let bank_items = entity_gateway.get_character_bank(&char1.id, &item::BankName("".into())).await.unwrap(); assert_eq!(bank_items.items.len(), 200); @@ -801,13 +801,13 @@ async fn test_deposit_meseta() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0xFFFFFFFF, @@ -815,7 +815,7 @@ async fn test_deposit_meseta() { item_amount: 0, meseta_amount: 23, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); let c1_bank_meseta = entity_gateway.get_bank_meseta(&char1.id, &item::BankName("".into())).await.unwrap(); @@ -838,13 +838,13 @@ async fn test_deposit_too_much_meseta() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0xFFFFFFFF, @@ -877,13 +877,13 @@ async fn test_deposit_meseta_when_bank_is_maxed() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0xFFFFFFFF, @@ -935,13 +935,13 @@ async fn test_withdraw_individual_item() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0x20000, @@ -949,7 +949,7 @@ async fn test_withdraw_individual_item() { item_amount: 0, meseta_amount: 0, unknown: 0, - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert!(packets.len() == 2); assert!(matches!(&packets[1], (ClientId(2), SendShipPacket::Message(Message {msg: GameMessage::CreateItem(create_item)})) @@ -995,13 +995,13 @@ async fn test_withdraw_stacked_item() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0x20000, @@ -1009,7 +1009,7 @@ async fn test_withdraw_stacked_item() { item_amount: 3, meseta_amount: 0, unknown: 0, - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert!(packets.len() == 2); assert!(matches!(&packets[1], (ClientId(2), SendShipPacket::Message(Message {msg: GameMessage::CreateItem(create_item)})) @@ -1054,13 +1054,13 @@ async fn test_withdraw_partial_stacked_item() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0x20000, @@ -1068,7 +1068,7 @@ async fn test_withdraw_partial_stacked_item() { item_amount: 2, meseta_amount: 0, unknown: 0, - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert!(packets.len() == 2); assert!(matches!(&packets[1], (ClientId(2), SendShipPacket::Message(Message {msg: GameMessage::CreateItem(create_item)})) @@ -1132,13 +1132,13 @@ async fn test_withdraw_stacked_item_with_stack_already_in_inventory() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0x20000, @@ -1146,7 +1146,7 @@ async fn test_withdraw_stacked_item_with_stack_already_in_inventory() { item_amount: 2, meseta_amount: 0, unknown: 0, - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert!(packets.len() == 2); assert!(matches!(&packets[1], (ClientId(2), SendShipPacket::Message(Message {msg: GameMessage::CreateItem(create_item)})) @@ -1204,13 +1204,13 @@ async fn test_withdraw_stacked_item_with_full_stack_in_inventory() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0x20000, @@ -1282,13 +1282,13 @@ async fn test_withdraw_individual_item_in_full_inventory() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0x20000, @@ -1350,13 +1350,13 @@ async fn test_withdraw_stacked_item_in_full_inventory() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0x20000, @@ -1437,13 +1437,13 @@ async fn test_withdraw_stacked_item_in_full_inventory_with_partial_stack() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0x20000, @@ -1451,7 +1451,7 @@ async fn test_withdraw_stacked_item_in_full_inventory_with_partial_stack() { item_amount: 2, meseta_amount: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let bank_items = entity_gateway.get_character_bank(&char1.id, &item::BankName("".into())).await.unwrap(); assert!(bank_items.items.len() == 0); @@ -1480,13 +1480,13 @@ async fn test_withdraw_meseta() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0xFFFFFFFF, @@ -1494,7 +1494,7 @@ async fn test_withdraw_meseta() { item_amount: 0, meseta_amount: 23, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); let c1_bank_meseta = entity_gateway.get_bank_meseta(&char1.id, &item::BankName("".into())).await.unwrap(); @@ -1517,13 +1517,13 @@ async fn test_withdraw_too_much_meseta() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packet = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packet = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0xFFFFFFFF, @@ -1556,13 +1556,13 @@ async fn test_withdraw_meseta_inventory_is_maxed() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankRequest(BankRequest { client: 0, target: 0, unknown: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packet = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { + let packet = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BankInteraction(BankInteraction { client: 0, target: 0, item_id: 0xFFFFFFFF, diff --git a/tests/test_character.rs b/tests/test_character.rs index 73eaf75..29812e9 100644 --- a/tests/test_character.rs +++ b/tests/test_character.rs @@ -21,9 +21,9 @@ async fn test_save_options() { log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; - ship.handle(ClientId(1), &RecvShipPacket::SaveOptions(SaveOptions{ + ship.handle(ClientId(1), RecvShipPacket::SaveOptions(SaveOptions{ options: 12345, - })).await.unwrap().for_each(drop); + })).await.unwrap(); let characters = entity_gateway.get_characters_by_user(&user1).await.unwrap(); let char = characters[0].as_ref().unwrap(); @@ -67,7 +67,7 @@ async fn test_change_keyboard_mappings() { // update from default2 to default4 // the client simply sends the full 364 bytes... - ship.handle(ClientId(1), &RecvShipPacket::KeyboardConfig(KeyboardConfig{ + ship.handle(ClientId(1), RecvShipPacket::KeyboardConfig(KeyboardConfig{ keyboard_config: [ 0, 0, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 115, 0, 0, 0, @@ -93,7 +93,7 @@ async fn test_change_keyboard_mappings() { 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 1, 0, 0, 0 ], - })).await.unwrap().for_each(drop); + })).await.unwrap(); let characters = entity_gateway.get_characters_by_user(&user1).await.unwrap(); let char = characters[0].as_ref().unwrap(); diff --git a/tests/test_character_data.rs b/tests/test_character_data.rs new file mode 100644 index 0000000..a379881 --- /dev/null +++ b/tests/test_character_data.rs @@ -0,0 +1,18 @@ +/* +use elseware::common::serverstate::{ClientId, ServerState}; +use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; +use elseware::entity::item; +use elseware::ship::ship::{ShipServerState, RecvShipPacket}; + +use libpso::packet::ship::*; +use libpso::packet::messages::*; + +#[path = "common.rs"] +mod common; +use common::*; + + +#[async_std::test] +async fn test_character_data_includes_material_usage() { +} +*/ diff --git a/tests/test_exp_gain.rs b/tests/test_exp_gain.rs index 0db6ba9..6821ad0 100644 --- a/tests/test_exp_gain.rs +++ b/tests/test_exp_gain.rs @@ -3,6 +3,7 @@ use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; use elseware::common::leveltable::CharacterLevelTable; use elseware::ship::ship::{ShipServerState, SendShipPacket, RecvShipPacket}; use elseware::ship::monster::MonsterType; +use elseware::ship::location::RoomId; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -25,27 +26,30 @@ async fn test_character_gains_exp() { create_room(&mut ship, ClientId(1), "room", "").await; let (enemy_id, exp) = { - let room = ship.blocks.0[0].rooms[0].as_ref().unwrap(); - let (enemy_id, map_enemy) = (0..).filter_map(|i| { - room.maps.enemy_by_id(i).map(|enemy| { - (i, enemy) - }).ok() - }).next().unwrap(); - let map_enemy_stats = room.monster_stats.get(&map_enemy.monster).unwrap(); - (enemy_id, map_enemy_stats.exp) + //let room = ship.blocks.0[0].rooms.get(RoomId(0)).as_ref().unwrap(); + ship.blocks.0[0].rooms.with(RoomId(0), |room| Box::pin(async move { + let (enemy_id, map_enemy) = (0..).filter_map(|i| { + room.maps.enemy_by_id(i).map(|enemy| { + (i, enemy) + }).ok() + }).next().unwrap(); + let map_enemy_stats = room.monster_stats.get(&map_enemy.monster).unwrap(); + (enemy_id, map_enemy_stats.exp) + })).await.unwrap() }; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::RequestExp(RequestExp{ + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::RequestExp(RequestExp { client: enemy_id as u8, target: 16, enemy_id: enemy_id as u16, client_id: 0, unused: 0, last_hitter: 1, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let c1 = ship.clients.get(&ClientId(1)).unwrap(); - assert!(exp == c1.character.exp); + ship.clients.with(ClientId(1), |client| Box::pin(async move { + assert!(exp == client.character.exp); + })).await; } #[async_std::test] @@ -63,29 +67,29 @@ async fn test_character_levels_up() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - let enemy_id = { - let room = ship.blocks.0[0].rooms[0].as_ref().unwrap(); + let enemy_id = ship.blocks.0[0].rooms.with(RoomId(0), |room| Box::pin(async move { (0..).filter_map(|i| { room.maps.enemy_by_id(i).map(|_| { i }).ok() }).next().unwrap() - }; + })).await.unwrap(); - let levelup_pkt = ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::RequestExp(RequestExp{ + let levelup_pkt = ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::RequestExp(RequestExp { client: enemy_id as u8, target: 16, enemy_id: enemy_id as u16, client_id: 0, unused: 0, last_hitter: 1, - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert!(matches!(levelup_pkt[1].1, SendShipPacket::Message(Message {msg: GameMessage::PlayerLevelUp(PlayerLevelUp {lvl: 2, ..})}))); let leveltable = CharacterLevelTable::default(); - let c1 = ship.clients.get(&ClientId(1)).unwrap(); - assert!(leveltable.get_level_from_exp(c1.character.char_class, c1.character.exp) == 2); + ship.clients.with(ClientId(1), |client| Box::pin(async move { + assert!(leveltable.get_level_from_exp(client.character.char_class, client.character.exp) == 2) + })).await.unwrap(); } #[async_std::test] @@ -102,34 +106,36 @@ async fn test_character_levels_up_multiple_times() { create_room(&mut ship, ClientId(1), "room", "").await; let (enemy_id, exp) = { - let room = ship.blocks.0[0].rooms[0].as_ref().unwrap(); - let (enemy_id, map_enemy) = (0..).filter_map(|i| { - room.maps.enemy_by_id(i).ok().and_then(|enemy| { - if enemy.monster == MonsterType::DarkFalz2 { - Some((i, enemy)) - } - else { - None - } - }) - }).next().unwrap(); - let map_enemy_stats = room.monster_stats.get(&map_enemy.monster).unwrap(); - (enemy_id, map_enemy_stats.exp) + ship.blocks.0[0].rooms.with(RoomId(0), |room| Box::pin(async move { + let (enemy_id, map_enemy) = (0..).filter_map(|i| { + room.maps.enemy_by_id(i).ok().and_then(|enemy| { + if enemy.monster == MonsterType::DarkFalz2 { + Some((i, enemy)) + } + else { + None + } + }) + }).next().unwrap(); + let map_enemy_stats = room.monster_stats.get(&map_enemy.monster).unwrap(); + (enemy_id, map_enemy_stats.exp) + })).await.unwrap() }; - let levelup_pkt = ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::RequestExp(RequestExp{ + let levelup_pkt = ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::RequestExp(RequestExp { client: enemy_id as u8, target: 16, enemy_id: enemy_id as u16, client_id: 0, unused: 0, last_hitter: 1, - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert!(matches!(levelup_pkt[1].1, SendShipPacket::Message(Message {msg: GameMessage::PlayerLevelUp(PlayerLevelUp {lvl: 8, ..})}))); - let c1 = ship.clients.get(&ClientId(1)).unwrap(); - assert!(exp == c1.character.exp); + let c1 = ship.clients.with(ClientId(1), |client| Box::pin(async move { + assert!(exp == client.character.exp); + })).await; } #[async_std::test] @@ -151,8 +157,7 @@ async fn test_one_character_gets_full_exp_and_other_attacker_gets_partial() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - let (enemy_id, exp) = { - let room = ship.blocks.0[0].rooms[0].as_ref().unwrap(); + let (enemy_id, exp) = ship.blocks.0[0].rooms.with(RoomId(0), |room| Box::pin(async move { let (enemy_id, map_enemy) = (0..).filter_map(|i| { room.maps.enemy_by_id(i).ok().and_then(|enemy| { if enemy.monster == MonsterType::DarkFalz2 { @@ -165,28 +170,30 @@ async fn test_one_character_gets_full_exp_and_other_attacker_gets_partial() { }).next().unwrap(); let map_enemy_stats = room.monster_stats.get(&map_enemy.monster).unwrap(); (enemy_id, map_enemy_stats.exp) - }; + })).await.unwrap(); - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::RequestExp(RequestExp{ + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::RequestExp(RequestExp { client: enemy_id as u8, target: 16, enemy_id: enemy_id as u16, client_id: 0, unused: 0, last_hitter: 1, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(2), &RecvShipPacket::Message(Message::new(GameMessage::RequestExp(RequestExp{ + ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::RequestExp(RequestExp { client: enemy_id as u8, target: 16, enemy_id: enemy_id as u16, client_id: 0, unused: 0, last_hitter: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let c1 = ship.clients.get(&ClientId(1)).unwrap(); - let c2 = ship.clients.get(&ClientId(2)).unwrap(); - assert!(c1.character.exp == exp); - assert!(c2.character.exp == (exp as f32 * 0.8) as u32); + ship.clients.with(ClientId(1), |client| Box::pin(async move { + assert!(client.character.exp == exp); + })).await.unwrap(); + ship.clients.with(ClientId(2), |client| Box::pin(async move { + assert!(client.character.exp == (exp as f32 * 0.8) as u32); + })).await.unwrap(); } diff --git a/tests/test_item_actions.rs b/tests/test_item_actions.rs index ec216da..77d52bc 100644 --- a/tests/test_item_actions.rs +++ b/tests/test_item_actions.rs @@ -63,22 +63,22 @@ async fn test_equip_unit_from_equip_menu() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerEquipItem(PlayerEquipItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerEquipItem(PlayerEquipItem { client: 0, target: 0, item_id: 0x10001, sub_menu: 9, unknown1: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); // case when someone tries to send invalid submenu? submenu is 9-12 in normal gameplay - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerEquipItem(PlayerEquipItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerEquipItem(PlayerEquipItem { client: 0, target: 0, item_id: 0x10002, sub_menu: 14, unknown1: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let equips = entity_gateway.get_character_equips(&char1.id).await.unwrap(); assert_eq!(equips.unit[0].unwrap(), item::ItemEntityId(2)); @@ -140,12 +140,12 @@ async fn test_unequip_armor_with_units() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerUnequipItem(PlayerUnequipItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUnequipItem(PlayerUnequipItem { client: 0, target: 0, item_id: 0x10000, unknown1: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let equips = entity_gateway.get_character_equips(&char1.id).await.unwrap(); assert!(equips.armor.is_none()); @@ -213,13 +213,13 @@ async fn test_sort_items() { }).unwrap(); - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::SortItems(SortItems { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::SortItems(SortItems { client: 255, target: 255, item_ids: [0x10001u32, 0x10002, 0x10000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF], - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); assert_eq!(inventory_items.items.len(), 3); diff --git a/tests/test_item_pickup.rs b/tests/test_item_pickup.rs index b2d2ce3..b216c13 100644 --- a/tests/test_item_pickup.rs +++ b/tests/test_item_pickup.rs @@ -51,7 +51,7 @@ async fn test_pick_up_individual_item() { let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap(); assert_eq!(p2_items.items.len(), 0); - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem { client: 0, target: 0, unknown1: 0, @@ -60,20 +60,20 @@ async fn test_pick_up_individual_item() { x: 0.0, y: 0.0, z: 0.0, - })))).await.unwrap().for_each(drop); + })))).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); - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { + ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { client: 0, target: 0, item_id: 0x10000, map_area: 0, unknown: [0; 3] - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); assert_eq!(p1_items.items.len(), 0); @@ -129,7 +129,7 @@ async fn test_pick_up_item_stack_of_items_already_in_inventory() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(2), &RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem { + ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem { client: 0, target: 0, unknown1: 0, @@ -138,15 +138,15 @@ async fn test_pick_up_item_stack_of_items_already_in_inventory() { x: 0.0, y: 0.0, z: 0.0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { client: 0, target: 0, item_id: 0x210000, map_area: 0, unknown: [0; 3] - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); assert_eq!(inventory_items.items.len(), 1); @@ -188,7 +188,7 @@ async fn test_pick_up_item_stack_of_items_not_already_held() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(2), &RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem { + ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem { client: 0, target: 0, unknown1: 0, @@ -197,15 +197,15 @@ async fn test_pick_up_item_stack_of_items_not_already_held() { x: 0.0, y: 0.0, z: 0.0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { client: 0, target: 0, item_id: 0x210000, map_area: 0, unknown: [0; 3] - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); assert_eq!(inventory_items.items.len(), 1); @@ -254,7 +254,7 @@ async fn test_pick_up_meseta_when_inventory_full() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(2), &RecvShipPacket::Message(Message::new(GameMessage::DropCoordinates(DropCoordinates { + ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::DropCoordinates(DropCoordinates { client: 0, target: 0, item_id: 0xFFFFFFFF, @@ -262,22 +262,22 @@ async fn test_pick_up_meseta_when_inventory_full() { room: 0, x: 0.0, z: 0.0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(2), &RecvShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem { + ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem { client: 0, target: 0, item_id: 0xFFFFFFFF, amount: 23, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { client: 0, target: 0, item_id: 0x00810001, map_area: 0, unknown: [0; 3] - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); assert_eq!(inventory_items.items.len(), 30); @@ -345,7 +345,7 @@ async fn test_pick_up_partial_stacked_item_when_inventory_is_otherwise_full() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(2), &RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem { + ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem { client: 0, target: 0, unknown1: 0, @@ -354,15 +354,15 @@ async fn test_pick_up_partial_stacked_item_when_inventory_is_otherwise_full() { x: 0.0, y: 0.0, z: 0.0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { client: 0, target: 0, item_id: 0x210000, map_area: 0, unknown: [0; 3] - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); assert_eq!(inventory_items.items.len(), 30); @@ -423,7 +423,7 @@ async fn test_can_not_pick_up_item_when_inventory_full() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(2), &RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem { + ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem { client: 0, target: 0, unknown1: 0, @@ -432,28 +432,28 @@ async fn test_can_not_pick_up_item_when_inventory_full() { x: 0.0, y: 0.0, z: 0.0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { client: 0, target: 0, item_id: 0x210000, map_area: 0, unknown: [0; 3] - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); 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(), 0); - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { + ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { client: 0, target: 0, item_id: 0x210000, map_area: 0, unknown: [0; 3] - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); assert_eq!(p1_items.items.len(), 30); @@ -478,7 +478,7 @@ async fn test_can_not_drop_more_meseta_than_is_held() { create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::DropCoordinates(DropCoordinates { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::DropCoordinates(DropCoordinates { client: 0, target: 0, item_id: 0xFFFFFFFF, @@ -486,9 +486,9 @@ async fn test_can_not_drop_more_meseta_than_is_held() { room: 0, x: 0.0, z: 0.0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let split_attempt = ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem { + let split_attempt = ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem { client: 0, target: 0, item_id: 0xFFFFFFFF, @@ -545,7 +545,7 @@ async fn test_pick_up_stack_that_would_exceed_stack_limit() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(2), &RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem { + ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem { client: 0, target: 0, unknown1: 0, @@ -554,15 +554,15 @@ async fn test_pick_up_stack_that_would_exceed_stack_limit() { x: 0.0, y: 0.0, z: 0.0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { client: 0, target: 0, item_id: 0x210000, map_area: 0, unknown: [0; 3] - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert!(packets.len() == 0); let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); @@ -596,7 +596,7 @@ async fn test_can_not_pick_up_meseta_when_full() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(2), &RecvShipPacket::Message(Message::new(GameMessage::DropCoordinates(DropCoordinates { + ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::DropCoordinates(DropCoordinates { client: 0, target: 0, item_id: 0xFFFFFFFF, @@ -604,22 +604,22 @@ async fn test_can_not_pick_up_meseta_when_full() { room: 0, x: 0.0, z: 0.0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(2), &RecvShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem { + ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem { client: 0, target: 0, item_id: 0xFFFFFFFF, amount: 23, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { client: 0, target: 0, item_id: 0x00810001, map_area: 0, unknown: [0; 3] - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert!(packets.len() == 0); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); @@ -650,7 +650,7 @@ async fn test_meseta_caps_at_999999_when_trying_to_pick_up_more() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(2), &RecvShipPacket::Message(Message::new(GameMessage::DropCoordinates(DropCoordinates { + ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::DropCoordinates(DropCoordinates { client: 0, target: 0, item_id: 0xFFFFFFFF, @@ -658,22 +658,22 @@ async fn test_meseta_caps_at_999999_when_trying_to_pick_up_more() { room: 0, x: 0.0, z: 0.0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(2), &RecvShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem { + ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem { client: 0, target: 0, item_id: 0xFFFFFFFF, amount: 23, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { client: 0, target: 0, item_id: 0x00810001, map_area: 0, unknown: [0; 3] - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); let c2_meseta = entity_gateway.get_character_meseta(&char2.id).await.unwrap(); @@ -714,7 +714,7 @@ async fn test_player_drops_partial_stack_and_other_player_picks_it_up() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::DropCoordinates(DropCoordinates { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::DropCoordinates(DropCoordinates { client: 0, target: 0, item_id: 0x10000, @@ -722,22 +722,22 @@ async fn test_player_drops_partial_stack_and_other_player_picks_it_up() { room: 0, x: 0.0, z: 0.0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem { client: 0, target: 0, item_id: 0x10000, amount: 2, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { + ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { client: 0, target: 0, item_id: 0x10003, map_area: 0, unknown: [0; 3] - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); assert_eq!(inventory_items.items.len(), 1); diff --git a/tests/test_item_use.rs b/tests/test_item_use.rs index 199dce7..574f948 100644 --- a/tests/test_item_use.rs +++ b/tests/test_item_use.rs @@ -43,11 +43,11 @@ async fn test_use_monomate() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { client: 0, target: 0, item_id: 0x10000, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); assert_eq!(inventory_items.items.len(), 2); @@ -90,16 +90,16 @@ async fn test_use_monomate_twice() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { client: 0, target: 0, item_id: 0x10000, - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { + })))).await.unwrap(); + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { client: 0, target: 0, item_id: 0x10000, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); assert_eq!(inventory_items.items.len(), 2); @@ -138,11 +138,11 @@ async fn test_use_last_monomate() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { client: 0, target: 0, item_id: 0x10000, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); @@ -178,11 +178,11 @@ async fn test_use_nonstackable_tool() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { client: 0, target: 0, item_id: 0x10000, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); assert_eq!(inventory_items.items.len(), 0); @@ -219,21 +219,21 @@ async fn test_use_materials() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { client: 0, target: 0, item_id: 0x10000, - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { + })))).await.unwrap(); + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { client: 0, target: 0, item_id: 0x10001, - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { + })))).await.unwrap(); + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { client: 0, target: 0, item_id: 0x10001, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); assert_eq!(inventory_items.items.len(), 2); diff --git a/tests/test_mags.rs b/tests/test_mags.rs index 3a6b0fd..1a7d687 100644 --- a/tests/test_mags.rs +++ b/tests/test_mags.rs @@ -58,12 +58,12 @@ async fn test_mag_feed() { create_room(&mut ship, ClientId(1), "room", "").await; for _ in 0..7usize { - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerFeedMag(PlayerFeedMag { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerFeedMag(PlayerFeedMag { client: 0, target: 0, mag_id: 0x10000, item_id: 0x10001, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); } let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); @@ -115,7 +115,7 @@ async fn test_mag_change_owner() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem { client: 0, target: 0, unknown1: 0, @@ -124,15 +124,15 @@ async fn test_mag_change_owner() { x: 0.0, y: 0.0, z: 0.0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { + ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { client: 0, target: 0, item_id: 0x10000, map_area: 0, unknown: [0; 3] - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let inventory_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap(); assert_eq!(inventory_items.items.len(), 1); @@ -198,11 +198,11 @@ async fn test_mag_cell() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { client: 0, target: 0, item_id: 0x10001, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); inventory_items.items[0].with_individual(|item| { diff --git a/tests/test_rooms.rs b/tests/test_rooms.rs index 96311fe..55635c6 100644 --- a/tests/test_rooms.rs +++ b/tests/test_rooms.rs @@ -2,6 +2,7 @@ use elseware::common::serverstate::{ClientId, ServerState}; use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; use elseware::entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; +use elseware::ship::location::RoomId; use libpso::packet::ship::*; //use libpso::packet::messages::*; @@ -63,11 +64,11 @@ async fn test_item_ids_reset_when_rejoining_rooms() { join_lobby(&mut ship, ClientId(2)).await; create_room(&mut ship, ClientId(1), "room", "").await; - let p = ship.handle(ClientId(2), &RecvShipPacket::MenuSelect(MenuSelect { + let p = ship.handle(ClientId(2), RecvShipPacket::MenuSelect(MenuSelect { menu: ROOM_MENU_ID, item: 0, - })).await.unwrap().collect::>(); - ship.handle(ClientId(2), &RecvShipPacket::DoneBursting(DoneBursting {})).await.unwrap().for_each(drop); + })).await.unwrap(); + ship.handle(ClientId(2), RecvShipPacket::DoneBursting(DoneBursting {})).await.unwrap(); match &p[1].1 { SendShipPacket::AddToRoom(add_to) => { @@ -81,10 +82,10 @@ async fn test_item_ids_reset_when_rejoining_rooms() { leave_room(&mut ship, ClientId(2)).await; - let p = ship.handle(ClientId(2), &RecvShipPacket::MenuSelect(MenuSelect { + let p = ship.handle(ClientId(2), RecvShipPacket::MenuSelect(MenuSelect { menu: ROOM_MENU_ID, item: 0, - })).await.unwrap().collect::>(); + })).await.unwrap(); match &p[1].1 { SendShipPacket::AddToRoom(add_to) => { @@ -108,12 +109,12 @@ async fn test_load_rare_monster_default_appear_rates() { create_room(&mut ship, ClientId(1), "room", "").await; // assume episode 1 - let room = ship.blocks.0[0].rooms[0].as_ref().unwrap(); - println!("rare monster table: {:?}", room.rare_monster_table); - let rates = &*room.rare_monster_table; - for (_monster, rate) in rates.clone().appear_rate { - assert_eq!(rate, 0.001953125f32); // 1/512 = 0.001953125 - } + ship.blocks.0[0].rooms.with(RoomId(0), |room| Box::pin(async move { + let rates = &*room.rare_monster_table; + for (_monster, rate) in rates.clone().appear_rate { + assert_eq!(rate, 0.001953125f32); // 1/512 = 0.001953125 + } + })).await.unwrap(); } #[async_std::test] @@ -127,7 +128,7 @@ async fn test_set_valid_quest_group() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - let packets = ship.handle(ClientId(1), &RecvShipPacket::RequestQuestList(RequestQuestList{flag: 0})).await.unwrap().collect::>(); + let packets = ship.handle(ClientId(1), RecvShipPacket::RequestQuestList(RequestQuestList{flag: 0})).await.unwrap(); match &packets[0].1 { SendShipPacket::QuestCategoryList(quest_cat) => { assert!(String::from_utf16_lossy(&quest_cat.quest_categories[0].name).starts_with("Retrieval")); @@ -147,7 +148,7 @@ async fn test_set_invalid_quest_group() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - let packets = ship.handle(ClientId(1), &RecvShipPacket::RequestQuestList(RequestQuestList{flag: 100})).await.unwrap().collect::>(); + let packets = ship.handle(ClientId(1), RecvShipPacket::RequestQuestList(RequestQuestList{flag: 100})).await.unwrap(); match &packets[0].1 { SendShipPacket::QuestCategoryList(quest_cat) => { // flag > quest category length should take the highest value allowed for quest category which is 1 in multimode (for govt quests) and 0 in other modes. @@ -174,7 +175,7 @@ async fn test_get_room_info() { join_lobby(&mut ship, ClientId(2)).await; create_room(&mut ship, ClientId(1), "room", "").await; let _expectedmsg = String::from("1 Lv1 GODmar\nHUmar Pioneer 2\n"); - let packets = ship.handle(ClientId(2), &RecvShipPacket::MenuDetail(MenuDetail{menu: 3, item: 0})).await.unwrap().collect::>(); + let packets = ship.handle(ClientId(2), RecvShipPacket::MenuDetail(MenuDetail{menu: 3, item: 0})).await.unwrap(); assert!(matches!(&packets[0], (ClientId(2), SendShipPacket::SmallLeftDialog(SmallLeftDialog{ padding: [17664, 1157645568], msg: _expectedmsg, @@ -196,7 +197,7 @@ async fn test_cannot_get_room_info_after_room_is_closed() { create_room(&mut ship, ClientId(1), "room", "").await; leave_room(&mut ship, ClientId(1)).await; let _expectedmsg = String::from("Game is no longer active!\0"); - let packets = ship.handle(ClientId(2), &RecvShipPacket::MenuDetail(MenuDetail{menu: 3, item: 0})).await.unwrap().collect::>(); + let packets = ship.handle(ClientId(2), RecvShipPacket::MenuDetail(MenuDetail{menu: 3, item: 0})).await.unwrap(); assert!(matches!(&packets[0], (ClientId(2), SendShipPacket::SmallLeftDialog(SmallLeftDialog{ padding: [17664, 1157645568], msg: _expectedmsg, @@ -218,7 +219,7 @@ async fn test_cannot_join_room_after_its_closed() { create_room(&mut ship, ClientId(1), "room", "").await; leave_room(&mut ship, ClientId(1)).await; let _expectedmsg = String::from("This room no longer exists!\0"); - let packets = ship.handle(ClientId(2), &RecvShipPacket::MenuSelect(MenuSelect{menu: 3, item: 0})).await.unwrap().collect::>(); + let packets = ship.handle(ClientId(2), RecvShipPacket::MenuSelect(MenuSelect{menu: 3, item: 0})).await.unwrap(); assert!(matches!(&packets[0], (ClientId(2), SendShipPacket::SmallDialog(SmallDialog{ padding: [0,0], msg: _expectedmsg, // wow yes cool rust is so great literally the best i can't put a String::from() directly in here. diff --git a/tests/test_shops.rs b/tests/test_shops.rs index c127c09..32244d0 100644 --- a/tests/test_shops.rs +++ b/tests/test_shops.rs @@ -1,7 +1,7 @@ use elseware::common::serverstate::{ClientId, ServerState}; use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; use elseware::entity::item; -use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; +use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket, ShipError}; use elseware::ship::room::Difficulty; use elseware::ship::items::state::ItemStateError; @@ -27,11 +27,11 @@ async fn test_player_opens_weapon_shop() { join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { client: 255, target: 255, shop_type: 1 - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert_eq!(packets.len(), 1); match &packets[0].1 { @@ -57,11 +57,11 @@ async fn test_player_opens_tool_shop() { join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { client: 255, target: 255, shop_type: 0 - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert_eq!(packets.len(), 1); match &packets[0].1 { @@ -87,11 +87,11 @@ async fn test_player_opens_armor_shop() { join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { client: 255, target: 255, shop_type: 2 - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert_eq!(packets.len(), 1); match &packets[0].1 { @@ -118,12 +118,12 @@ async fn test_player_buys_from_weapon_shop() { join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { client: 255, target: 255, shop_type: 1 - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + })))).await.unwrap(); + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { client: 255, target: 255, item_id: 0x10000, @@ -131,7 +131,7 @@ async fn test_player_buys_from_weapon_shop() { shop_index: 0, amount: 1, unknown1: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert!(c1_meseta.0 < 999999); @@ -156,12 +156,12 @@ async fn test_player_buys_from_tool_shop() { join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { client: 255, target: 255, shop_type: 0, - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + })))).await.unwrap(); + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { client: 255, target: 255, item_id: 0x10000, @@ -169,7 +169,7 @@ async fn test_player_buys_from_tool_shop() { shop_index: 0, amount: 1, unknown1: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert!(c1_meseta.0 < 999999); @@ -193,12 +193,12 @@ async fn test_player_buys_multiple_from_tool_shop() { join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { client: 255, target: 255, shop_type: 0, - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + })))).await.unwrap(); + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { client: 255, target: 255, item_id: 0x10000, @@ -206,7 +206,7 @@ async fn test_player_buys_multiple_from_tool_shop() { shop_index: 0, amount: 5, unknown1: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert_eq!(c1_meseta.0, 999749); @@ -234,12 +234,12 @@ async fn test_player_buys_from_armor_shop() { join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { client: 255, target: 255, shop_type: 2 - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + })))).await.unwrap(); + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { client: 255, target: 255, item_id: 0x10000, @@ -247,7 +247,7 @@ async fn test_player_buys_from_armor_shop() { shop_index: 0, amount: 1, unknown1: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert!(c1_meseta.0 < 999999); @@ -288,12 +288,12 @@ async fn test_player_sells_3_attr_weapon_to_shop() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { client: 0, target: 0, item_id: 0x10000, amount: 1, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert_eq!(c1_meseta.0, 4406); @@ -319,12 +319,12 @@ async fn test_other_clients_see_purchase() { create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Normal).await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { client: 255, target: 255, shop_type: 1 - })))).await.unwrap().for_each(drop); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + })))).await.unwrap(); + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { client: 255, target: 255, item_id: 0x10000, @@ -332,7 +332,7 @@ async fn test_other_clients_see_purchase() { shop_index: 0, amount: 1, unknown1: 0, - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert_eq!(packets.len(), 1); assert_eq!(packets[0].0, ClientId(2)); @@ -370,12 +370,12 @@ async fn test_other_clients_see_stacked_purchase() { create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Normal).await; join_room(&mut ship, ClientId(2), 0).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { client: 255, target: 255, shop_type: 1 - })))).await.unwrap().for_each(drop); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + })))).await.unwrap(); + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { client: 255, target: 255, item_id: 0x10000, @@ -383,7 +383,7 @@ async fn test_other_clients_see_stacked_purchase() { shop_index: 0, amount: 1, unknown1: 0, - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert_eq!(packets.len(), 1); assert_eq!(packets[0].0, ClientId(2)); @@ -406,12 +406,12 @@ async fn test_buying_item_without_enough_mseseta() { join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Normal).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { client: 255, target: 255, shop_type: 1 - })))).await.unwrap().for_each(drop); - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + })))).await.unwrap(); + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { client: 255, target: 255, item_id: 0x10000, @@ -444,12 +444,12 @@ async fn test_player_double_buys_from_tool_shop() { join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { client: 255, target: 255, shop_type: 0, - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + })))).await.unwrap(); + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { client: 255, target: 255, item_id: 0x10000, @@ -457,8 +457,8 @@ async fn test_player_double_buys_from_tool_shop() { shop_index: 0, amount: 3, unknown1: 0, - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + })))).await.unwrap(); + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { client: 255, target: 255, item_id: 0x10001, @@ -466,8 +466,8 @@ async fn test_player_double_buys_from_tool_shop() { shop_index: 1, amount: 2, unknown1: 0, - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + })))).await.unwrap(); + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { client: 255, target: 255, item_id: 0x10002, @@ -475,7 +475,7 @@ async fn test_player_double_buys_from_tool_shop() { shop_index: 0, amount: 4, unknown1: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert!(c1_meseta.0 < 999999); @@ -509,11 +509,11 @@ async fn test_techs_disappear_from_shop_when_bought() { join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { client: 255, target: 255, shop_type: 0, - })))).await.unwrap().collect::>(); + })))).await.unwrap(); let first_tech = match &packets[0].1 { SendShipPacket::Message(Message {msg: GameMessage::ShopList(shop_list)}) => { @@ -527,7 +527,7 @@ async fn test_techs_disappear_from_shop_when_bought() { _ => panic!(""), }; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { client: 255, target: 255, item_id: 0x10000, @@ -535,8 +535,8 @@ async fn test_techs_disappear_from_shop_when_bought() { shop_index: first_tech as u8, amount: 1, unknown1: 0, - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + })))).await.unwrap(); + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { client: 255, target: 255, item_id: 0x10001, @@ -544,7 +544,7 @@ async fn test_techs_disappear_from_shop_when_bought() { shop_index: first_tech as u8, amount: 1, unknown1: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); p1_items.items[0].with_individual(|item1| { @@ -571,11 +571,11 @@ async fn test_units_disappear_from_shop_when_bought() { join_lobby(&mut ship, ClientId(1)).await; create_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; - let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { + let packets = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::ShopRequest(ShopRequest { client: 255, target: 255, shop_type: 2, - })))).await.unwrap().collect::>(); + })))).await.unwrap(); let first_unit = match &packets[0].1 { SendShipPacket::Message(Message {msg: GameMessage::ShopList(shop_list)}) => { @@ -589,7 +589,7 @@ async fn test_units_disappear_from_shop_when_bought() { _ => panic!(""), }; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { client: 255, target: 255, item_id: 0x10000, @@ -597,8 +597,8 @@ async fn test_units_disappear_from_shop_when_bought() { shop_index: first_unit as u8, amount: 1, unknown1: 0, - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { + })))).await.unwrap(); + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::BuyItem(BuyItem { client: 255, target: 255, item_id: 0x10001, @@ -606,7 +606,7 @@ async fn test_units_disappear_from_shop_when_bought() { shop_index: first_unit as u8, amount: 1, unknown1: 0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); p1_items.items[0].with_individual(|item1| { @@ -649,12 +649,12 @@ async fn test_player_sells_untekked_weapon() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { client: 0, target: 0, item_id: 0x10000, amount: 1, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert_eq!(c1_meseta.0, 1); @@ -693,12 +693,12 @@ async fn test_player_sells_rare_item() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { client: 0, target: 0, item_id: 0x10000, amount: 1, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert_eq!(c1_meseta.0, 10); @@ -736,12 +736,12 @@ async fn test_player_sells_partial_photon_drop_stack() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { client: 0, target: 0, item_id: 0x10000, amount: 3, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert_eq!(c1_meseta.0, 3000); @@ -777,12 +777,12 @@ async fn test_player_sells_basic_frame() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { client: 0, target: 0, item_id: 0x10000, amount: 1, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert_eq!(c1_meseta.0, 24); @@ -818,12 +818,12 @@ async fn test_player_sells_max_frame() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { client: 0, target: 0, item_id: 0x10000, amount: 1, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert_eq!(c1_meseta.0, 74); @@ -858,12 +858,12 @@ async fn test_player_sells_basic_barrier() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { client: 0, target: 0, item_id: 0x10000, amount: 1, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert_eq!(c1_meseta.0, 69); @@ -898,12 +898,12 @@ async fn test_player_sells_max_barrier() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { client: 0, target: 0, item_id: 0x10000, amount: 1, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert_eq!(c1_meseta.0, 122); @@ -937,12 +937,12 @@ async fn test_player_sells_1_star_minusminus_unit() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { client: 0, target: 0, item_id: 0x10000, amount: 1, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert_eq!(c1_meseta.0, 125); @@ -976,12 +976,12 @@ async fn test_player_sells_5_star_plusplus_unit() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { client: 0, target: 0, item_id: 0x10000, amount: 1, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert_eq!(c1_meseta.0, 625); @@ -1017,12 +1017,12 @@ async fn test_player_sells_rare_frame() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { client: 0, target: 0, item_id: 0x10000, amount: 1, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert_eq!(c1_meseta.0, 10); @@ -1057,12 +1057,12 @@ async fn test_player_sells_rare_barrier() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { client: 0, target: 0, item_id: 0x10000, amount: 1, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert_eq!(c1_meseta.0, 10); @@ -1096,12 +1096,12 @@ async fn test_player_sells_rare_unit() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { client: 0, target: 0, item_id: 0x10000, amount: 1, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert_eq!(c1_meseta.0, 10); @@ -1136,13 +1136,14 @@ async fn test_player_cant_sell_if_meseta_would_go_over_max() { join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - let ack = ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { + let ack = ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerSoldItem(PlayerSoldItem { client: 0, target: 0, item_id: 0x10000, amount: 1, })))).await.err().unwrap(); - assert!(matches!(ack.downcast::().unwrap(), ItemStateError::FullOfMeseta)); + //assert_eq!(ack, ShipError::ItemStateError(ItemStateError::FullOfMeseta)); + assert!(matches!(ack.downcast::().unwrap(), ShipError::ItemStateError(ItemStateError::FullOfMeseta))); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert_eq!(c1_meseta.0, 999995); diff --git a/tests/test_trade.rs b/tests/test_trade.rs index fd6efe0..9175716 100644 --- a/tests/test_trade.rs +++ b/tests/test_trade.rs @@ -5,8 +5,6 @@ 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 elseware::ship::items::state::ItemStateError; -use elseware::ship::items::inventory::InventoryError; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -16,45 +14,45 @@ mod common; use common::*; async fn initialize_trade(ship: &mut ShipServerState, client1: ClientId, client2: ClientId) { - ship.handle(client1, &RecvShipPacket::DirectMessage(DirectMessage::new(client2.0 as u32 -1, GameMessage::TradeRequest(TradeRequest { + 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().for_each(drop); + })))).await.unwrap(); - ship.handle(client2, &RecvShipPacket::DirectMessage(DirectMessage::new(client1.0 as u32 -1, GameMessage::TradeRequest(TradeRequest { + 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().for_each(drop); + })))).await.unwrap(); } async fn confirm_trade(ship: &mut ShipServerState, client1: ClientId, client2: ClientId) { - ship.handle(client1, &RecvShipPacket::DirectMessage(DirectMessage::new(client2.0 as u32 -1, GameMessage::TradeRequest(TradeRequest { + 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().for_each(drop); + })))).await.unwrap(); - ship.handle(client2, &RecvShipPacket::DirectMessage(DirectMessage::new(client1.0 as u32 -1, GameMessage::TradeRequest(TradeRequest { + 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().for_each(drop); + })))).await.unwrap(); } async fn finalconfirm_trade(ship: &mut ShipServerState, client1: ClientId, client2: ClientId) { - ship.handle(client1, &RecvShipPacket::DirectMessage(DirectMessage::new(client2.0 as u32 -1, GameMessage::TradeRequest(TradeRequest { + 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().for_each(drop); + })))).await.unwrap(); - ship.handle(client2, &RecvShipPacket::DirectMessage(DirectMessage::new(client1.0 as u32 -1, GameMessage::TradeRequest(TradeRequest { + 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().for_each(drop); + })))).await.unwrap(); } #[derive(Default)] @@ -154,11 +152,11 @@ async fn test_trade_one_individual_item() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -166,30 +164,30 @@ async fn test_trade_one_individual_item() { let titems = TradeItemBuilder::default() .individual(&p1_items.items[0], 0x10000) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 0); - let ack = ship.handle(ClientId(2), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 0, items: Default::default(), - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 {..}), @@ -255,42 +253,42 @@ async fn test_trade_player2_to_player1() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x210000, 1) - })))).await.unwrap().for_each(drop); + })))).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 { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 0, items: Default::default(), - })).await.unwrap().collect::>(); + })).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 { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 {..}), @@ -356,42 +354,42 @@ async fn test_reverse_trade_ack_order() { initialize_trade(&mut ship, ClientId(2), ClientId(1)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); + })))).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 { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 0, items: Default::default(), - })).await.unwrap().collect::>(); + })).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 { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 {..}), @@ -460,11 +458,11 @@ async fn test_trade_one_stacked_item() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 2) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -472,30 +470,30 @@ async fn test_trade_one_stacked_item() { let titems = TradeItemBuilder::default() .stacked(&p1_items.items[0], 0x10000, 2) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 0); - let ack = ship.handle(ClientId(2), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 0, items: Default::default(), - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 {..}), @@ -565,11 +563,11 @@ async fn test_trade_partial_stacked_item() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -577,30 +575,30 @@ async fn test_trade_partial_stacked_item() { let titems = TradeItemBuilder::default() .stacked(&p1_items.items[0], 0x10000, 1) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 0); - let ack = ship.handle(ClientId(2), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 0, items: Default::default(), - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 {..}), @@ -681,17 +679,17 @@ async fn test_trade_individual_both() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 0, target: 0, trade: TradeRequestCommand::AddItem(0x210000, 1) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -699,33 +697,33 @@ async fn test_trade_individual_both() { let titems = TradeItemBuilder::default() .individual(&p1_items.items[0], 0x10000) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).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 { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 { @@ -853,17 +851,17 @@ async fn test_trade_stacked_both() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 2) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { client: 0, target: 0, trade: TradeRequestCommand::AddItem(0x210000, 3) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -871,33 +869,33 @@ async fn test_trade_stacked_both() { let titems = TradeItemBuilder::default() .stacked(&p1_items.items[0], 0x10000, 2) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).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 { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 { @@ -1023,17 +1021,17 @@ async fn test_trade_partial_stack_both() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { client: 0, target: 0, trade: TradeRequestCommand::AddItem(0x210000, 2) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -1041,33 +1039,33 @@ async fn test_trade_partial_stack_both() { let titems = TradeItemBuilder::default() .stacked(&p1_items.items[0], 0x10000, 1) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).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 { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 { @@ -1199,17 +1197,17 @@ async fn test_trade_same_stacked_item_to_eachother() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { client: 0, target: 0, trade: TradeRequestCommand::AddItem(0x210000, 3) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -1217,33 +1215,33 @@ async fn test_trade_same_stacked_item_to_eachother() { let titems = TradeItemBuilder::default() .stacked(&p1_items.items[0], 0x10000, 1) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).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 { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 { @@ -1371,11 +1369,11 @@ async fn test_trade_stacked_when_already_have_partial_stack() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 2) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -1383,30 +1381,30 @@ async fn test_trade_stacked_when_already_have_partial_stack() { let titems = TradeItemBuilder::default() .stacked(&p1_items.items[0], 0x10000, 2) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 0); - let ack = ship.handle(ClientId(2), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 0, items: Default::default(), - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 { @@ -1508,17 +1506,17 @@ async fn test_trade_individual_for_stacked() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { client: 0, target: 0, trade: TradeRequestCommand::AddItem(0x210000, 2) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -1526,33 +1524,33 @@ async fn test_trade_individual_for_stacked() { let titems = TradeItemBuilder::default() .individual(&p1_items.items[0], 0x10000) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).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 { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 { @@ -1700,27 +1698,27 @@ async fn test_trade_multiple_individual() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { client: 0, target: 0, trade: TradeRequestCommand::AddItem(0x210000, 1) - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -1729,34 +1727,34 @@ async fn test_trade_multiple_individual() { .individual(&p1_items.items[0], 0x10000) .individual(&p1_items.items[1], 0x10001) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 2, items: titems, - })).await.unwrap().collect::>(); + })).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 { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 2, items: titems, - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 { @@ -1971,27 +1969,27 @@ async fn test_trade_multiple_stacked() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 2) - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { client: 0, target: 0, trade: TradeRequestCommand::AddItem(0x210000, 3) - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -2001,34 +1999,34 @@ async fn test_trade_multiple_stacked() { .stacked(&p1_items.items[0], 0x10000, 2) .stacked(&p1_items.items[1], 0x10001, 2) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 2, items: titems, - })).await.unwrap().collect::>(); + })).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 { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 2, items: titems, - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 { @@ -2216,11 +2214,11 @@ async fn test_trade_not_enough_inventory_space_individual() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -2228,30 +2226,30 @@ async fn test_trade_not_enough_inventory_space_individual() { let titems = TradeItemBuilder::default() .individual(&p1_items.items[0], 0x10000) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 0); - let ack = ship.handle(ClientId(2), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 0, items: Default::default(), - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed { + })).await.unwrap(); assert_eq!(ack, vec![ @@ -2334,11 +2332,11 @@ async fn test_trade_not_enough_inventory_space_stacked() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 2) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -2346,30 +2344,30 @@ async fn test_trade_not_enough_inventory_space_stacked() { let titems = TradeItemBuilder::default() .stacked(&p1_items.items[0], 0x10000, 2) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 0); - let ack = ship.handle(ClientId(2), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 0, items: Default::default(), - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed { + })).await.unwrap(); assert_eq!(ack, vec![ @@ -2448,11 +2446,11 @@ async fn test_trade_stack_too_big() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 4) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -2460,30 +2458,30 @@ async fn test_trade_stack_too_big() { let titems = TradeItemBuilder::default() .stacked(&p1_items.items[0], 0x10000, 4) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 0); - let ack = ship.handle(ClientId(2), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 0, items: Default::default(), - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed { + })).await.unwrap(); assert_eq!(ack, vec![ @@ -2522,11 +2520,11 @@ async fn test_trade_meseta() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0xFFFFFF01, 23) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -2534,30 +2532,30 @@ async fn test_trade_meseta() { let titems = TradeItemBuilder::default() .meseta(23) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 0); - let ack = ship.handle(ClientId(2), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 0, items: Default::default(), - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 {..}), @@ -2604,11 +2602,11 @@ async fn test_trade_too_much_meseta() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0xFFFFFF01, 2000) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -2616,12 +2614,12 @@ async fn test_trade_too_much_meseta() { let titems = TradeItemBuilder::default() .meseta(2000) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 2); assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..)))); assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..)))); @@ -2656,11 +2654,11 @@ async fn test_trade_invalid_amount_of_meseta() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0xFFFFFF01, 5000) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -2668,12 +2666,12 @@ async fn test_trade_invalid_amount_of_meseta() { let titems = TradeItemBuilder::default() .meseta(5000) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 2); assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..)))); assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..)))); @@ -2708,11 +2706,11 @@ async fn test_trade_meseta_request_and_items_dont_match() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0xFFFFFF01, 50) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -2720,12 +2718,12 @@ async fn test_trade_meseta_request_and_items_dont_match() { let titems = TradeItemBuilder::default() .meseta(23) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 2); assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..)))); assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..)))); @@ -2757,11 +2755,11 @@ async fn test_player_declined_trade() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - let ack = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + let ack = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::Cancel - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert_eq!(ack.len(), 2); assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..)))); assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..)))); @@ -2810,19 +2808,19 @@ async fn test_back_out_of_trade_last_minute() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); + })))).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 { + let ack = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::Cancel - })))).await.unwrap().collect::>(); + })))).await.unwrap(); assert_eq!(ack.len(), 2); assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..)))); assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..)))); @@ -2906,27 +2904,27 @@ async fn test_valid_trade_when_both_inventories_are_full() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { client: 0, target: 0, trade: TradeRequestCommand::AddItem(0x210000, 1) - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -2935,34 +2933,34 @@ async fn test_valid_trade_when_both_inventories_are_full() { .individual(&p1_items.items[0], 0x10000) .individual(&p1_items.items[1], 0x10001) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 2, items: titems, - })).await.unwrap().collect::>(); + })).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 { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 2, items: titems, - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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(); @@ -3048,32 +3046,32 @@ async fn test_invalid_trade_when_both_inventories_are_full() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); + })))).await.unwrap(); - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { client: 0, target: 0, trade: TradeRequestCommand::AddItem(0x210000, 1) - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -3083,34 +3081,34 @@ async fn test_invalid_trade_when_both_inventories_are_full() { .individual(&p1_items.items[1], 0x10001) .individual(&p1_items.items[1], 0x10002) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 3, items: titems, - })).await.unwrap().collect::>(); + })).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 { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 2, items: titems, - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed { + })).await.unwrap(); assert_eq!(ack, vec![ @@ -3151,7 +3149,7 @@ async fn test_client_tries_to_start_two_trades() { 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 { + let ack = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 0, target: 0, trade: TradeRequestCommand::Initialize(TradeRequestInitializeCommand::Initialize, 0) @@ -3184,14 +3182,14 @@ async fn test_client_tries_trading_with_client_already_trading() { 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 { + 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::().unwrap(), ShipError::TradeError(TradeError::OtherAlreadyInTrade))); - let ack = ship.handle(ClientId(3), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + let ack = ship.handle(ClientId(3), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 2, target: 0, trade: TradeRequestCommand::Initialize(TradeRequestInitializeCommand::Initialize, 1) @@ -3244,21 +3242,21 @@ async fn test_add_then_remove_individual_item() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -3266,30 +3264,30 @@ async fn test_add_then_remove_individual_item() { let titems = TradeItemBuilder::default() .individual(&p1_items.items[1], 0x10001) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 0); - let ack = ship.handle(ClientId(2), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 0, items: Default::default(), - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 {..}), @@ -3375,21 +3373,21 @@ async fn test_add_then_remove_stacked_item() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 2) - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -3397,30 +3395,30 @@ async fn test_add_then_remove_stacked_item() { let titems = TradeItemBuilder::default() .stacked(&p1_items.items[1], 0x10001, 2) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 0); - let ack = ship.handle(ClientId(2), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 0, items: Default::default(), - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 {..}), @@ -3510,21 +3508,21 @@ async fn test_add_then_remove_partial_stack() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 2) - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -3533,30 +3531,30 @@ async fn test_add_then_remove_partial_stack() { .stacked(&p1_items.items[0], 0x10000, 1) .stacked(&p1_items.items[1], 0x10001, 2) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 2, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 0); - let ack = ship.handle(ClientId(2), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 0, items: Default::default(), - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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(); @@ -3594,16 +3592,16 @@ async fn test_add_then_remove_meseta() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0xFFFFFF01, 23) - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -3611,30 +3609,30 @@ async fn test_add_then_remove_meseta() { let titems = TradeItemBuilder::default() .meseta(18) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 0); - let ack = ship.handle(ClientId(2), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 0, items: Default::default(), - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 {..}), @@ -3700,11 +3698,11 @@ async fn test_items_to_trade_data_does_not_match() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -3724,12 +3722,12 @@ async fn test_items_to_trade_data_does_not_match() { let titems = TradeItemBuilder::default() .individual(&new_item, 0x10000) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 2); assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..)))); assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..)))); @@ -3783,11 +3781,11 @@ async fn test_items_to_trade_id_does_not_match() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -3795,12 +3793,12 @@ async fn test_items_to_trade_id_does_not_match() { let titems = TradeItemBuilder::default() .individual(&p1_items.items[0], 0x10001) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 2); assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..)))); assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..)))); @@ -3857,11 +3855,11 @@ async fn test_stack_is_same_amount_in_request_and_items_to_trade() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 2) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -3869,12 +3867,12 @@ async fn test_stack_is_same_amount_in_request_and_items_to_trade() { let titems = TradeItemBuilder::default() .stacked(&p1_items.items[0], 0x10000, 1) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 2); assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..)))); assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..)))); @@ -3931,11 +3929,11 @@ async fn test_stack_is_same_amount_in_request_and_items_to_trade2() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -3943,12 +3941,12 @@ async fn test_stack_is_same_amount_in_request_and_items_to_trade2() { let titems = TradeItemBuilder::default() .stacked(&p1_items.items[0], 0x10000, 2) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 2); assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..)))); assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..)))); @@ -4027,16 +4025,16 @@ async fn test_items_to_trade_count_less_than() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -4045,12 +4043,12 @@ async fn test_items_to_trade_count_less_than() { .individual(&p1_items.items[0], 0x10000) .individual(&p1_items.items[1], 0x10001) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 2); assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..)))); assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..)))); @@ -4131,21 +4129,21 @@ async fn test_items_to_trade_count_greater_than() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -4155,12 +4153,12 @@ async fn test_items_to_trade_count_greater_than() { .individual(&p1_items.items[1], 0x10001) .meseta(5) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 4, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 2); assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..)))); assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..)))); @@ -4239,16 +4237,16 @@ async fn test_items_to_trade_count_mismatch_with_meseta() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + })))).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().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -4257,12 +4255,12 @@ async fn test_items_to_trade_count_mismatch_with_meseta() { .individual(&p1_items.items[0], 0x10000) .individual(&p1_items.items[1], 0x10001) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 3, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 2); assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..)))); assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..)))); @@ -4316,11 +4314,11 @@ async fn test_dropping_item_after_trade() { initialize_trade(&mut ship, ClientId(1), ClientId(2)).await; - ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 1, target: 0, trade: TradeRequestCommand::AddItem(0x10000, 1) - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); confirm_trade(&mut ship, ClientId(1), ClientId(2)).await; finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await; @@ -4328,30 +4326,30 @@ async fn test_dropping_item_after_trade() { let titems = TradeItemBuilder::default() .individual(&p1_items.items[0], 0x10000) .build(); - let ack = ship.handle(ClientId(1), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 1, unknown2: 0, count: 1, items: titems, - })).await.unwrap().collect::>(); + })).await.unwrap(); assert_eq!(ack.len(), 0); - let ack = ship.handle(ClientId(2), &RecvShipPacket::ItemsToTrade(ItemsToTrade { + let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade { trade_target: 0, unknown2: 0, count: 0, items: Default::default(), - })).await.unwrap().collect::>(); + })).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().collect::>(); + 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().collect::>(); + 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 {..}), @@ -4368,7 +4366,7 @@ async fn test_dropping_item_after_trade() { 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 { + let _ack = ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem { client: 0, target: 0, unknown1: 0, @@ -4377,7 +4375,7 @@ async fn test_dropping_item_after_trade() { x: 0.0, y: 0.0, z: 0.0, - })))).await.unwrap().for_each(drop); + })))).await.unwrap(); let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); assert_eq!(p1_items.items.len(), 0); From 3a50cd7ba19d23dffac0e48ec752f6cdd263a641 Mon Sep 17 00:00:00 2001 From: jake Date: Tue, 18 Oct 2022 16:21:45 -0600 Subject: [PATCH 4/9] fix the standalone binaries --- src/bin/login.rs | 27 +++++---- src/bin/main.rs | 144 ++++++++++++++--------------------------------- src/bin/patch.rs | 8 +-- src/bin/ship.rs | 23 +++++--- 4 files changed, 75 insertions(+), 127 deletions(-) diff --git a/src/bin/login.rs b/src/bin/login.rs index 6490973..f8b6b94 100644 --- a/src/bin/login.rs +++ b/src/bin/login.rs @@ -1,12 +1,10 @@ use log::{info}; -//use elseware::entity::gateway::postgres::PostgresGateway; +use elseware::entity::gateway::postgres::PostgresGateway; use elseware::login::login::LoginServerState; use elseware::login::character::CharacterServerState; -//use elseware::common::mainloop::{login_mainloop, character_mainloop}; -//use elseware::common::interserver::AuthToken; +use elseware::common::interserver::AuthToken; fn main() { - /* let colors = fern::colors::ColoredLevelConfig::new() .error(fern::colors::Color::Red) .warn(fern::colors::Color::Yellow) @@ -38,16 +36,23 @@ fn main() { let shipgate_token = std::env::var("SHIPGATE_TOKEN").unwrap(); let entity_gateway = PostgresGateway::new(&db_host, &db_dbname, &db_username, &db_password); - let thread_entity_gateway = entity_gateway.clone(); - let login_state = LoginServerState::new(thread_entity_gateway, charserv_ip); - let login_loop = login_mainloop(login_state, elseware::login::login::LOGIN_PORT); - + let login_state = LoginServerState::new(entity_gateway.clone(), charserv_ip); + let login_loop = async_std::task::spawn(async move { + elseware::common::mainloop::run_server(login_state, elseware::login::login::LOGIN_PORT).await; + }); + let char_state = CharacterServerState::new(entity_gateway, AuthToken(shipgate_token)); - let character_loop = character_mainloop(char_state, elseware::login::character::CHARACTER_PORT, elseware::login::login::COMMUNICATION_PORT); + let sub_char_state = char_state.clone(); + let character_loop = async_std::task::spawn(async move { + elseware::common::mainloop::run_server(sub_char_state, elseware::login::character::CHARACTER_PORT).await; + }); + + let inter_character_loop = async_std::task::spawn(async move { + elseware::common::mainloop::run_interserver_listen(char_state, elseware::login::login::COMMUNICATION_PORT).await; + }); info!("[auth/character] starting server"); async_std::task::block_on(async move { - futures::future::join_all(vec![login_loop, character_loop]).await + futures::future::join_all(vec![login_loop, character_loop, inter_character_loop]).await }); - */ } diff --git a/src/bin/main.rs b/src/bin/main.rs index 9054c28..3195373 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,21 +1,18 @@ use std::net::Ipv4Addr; use log::{info}; -use async_std::channel; -use elseware::patch::patch::{PatchServerState, generate_patch_tree, load_config, load_motd}; +use elseware::common::interserver::AuthToken; use elseware::login::login::LoginServerState; use elseware::login::character::CharacterServerState; -//use elseware::ship::ship::ShipServerStateBuilder; -use elseware::entity::account::{NewUserAccountEntity, NewUserSettingsEntity}; +use elseware::patch::patch::{PatchServerState, generate_patch_tree, load_config, load_motd}; +use elseware::ship::ship::ShipServerStateBuilder; + #[allow(unused_imports)] -//use elseware::entity::gateway::{EntityGateway, InMemoryGateway, PostgresGateway}; -use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; +use elseware::entity::gateway::{EntityGateway, InMemoryGateway, PostgresGateway}; +use elseware::entity::account::{NewUserAccountEntity, NewUserSettingsEntity}; use elseware::entity::character::NewCharacterEntity; use elseware::entity::item::{NewItemEntity, ItemDetail, InventoryItemEntity}; -use elseware::common::interserver::AuthToken; - use elseware::entity::item; -use elseware::common::mainloop::*; fn setup_logger() { let colors = fern::colors::ColoredLevelConfig::new() @@ -327,60 +324,14 @@ fn main() { }; entity_gateway.set_character_equips(&character.id, &equipped).await.unwrap(); - let inventory = item::InventoryEntity::new(vec![InventoryItemEntity::from(item0), item1.into(), item2_w.into(), item3.into(), item4.into(), item5_m.into(), item6.into(), item6_1.into(), item7_a.into(), item8_s.into(), item9_u0.into(), item10_u1.into(), item11_u2.into(), item12_u3.into(), item13.into(), item14.into(), monomates.into()]); + let inventory = item::InventoryEntity::new(vec![InventoryItemEntity::from(item0), item1.into(), item2_w.into(), item3.into(), + item4.into(), item5_m.into(), item6.into(), item6_1.into(), item7_a.into(), + item8_s.into(), item9_u0.into(), item10_u1.into(), item11_u2.into(), item12_u3.into(), + item13.into(), item14.into(), monomates.into()]); entity_gateway.set_character_inventory(&character.id, &inventory).await.unwrap(); entity_gateway.set_character_bank(&character.id, &item::BankEntity::default(), &item::BankName("".into())).await.unwrap(); } - /* - info!("[patch] starting server"); - let patch_config = load_config(); - let patch_motd = load_motd(); - let (patch_file_tree, patch_file_lookup) = generate_patch_tree(patch_config.path.as_str()); - let patch_state = Box::new(PatchServerState::new(patch_file_tree, patch_file_lookup, patch_motd)); - let patch_loop = patch_mainloop(*patch_state, patch_config.port); - - let thread_entity_gateway = entity_gateway.clone(); - info!("[auth] starting server"); - let login_state = Box::new(LoginServerState::new(thread_entity_gateway, "127.0.0.1".parse().unwrap())); - let login_loop = login_mainloop(*login_state, elseware::login::login::LOGIN_PORT); - - let thread_entity_gateway = entity_gateway.clone(); - info!("[character] starting server"); - let char_state = Box::new(CharacterServerState::new(thread_entity_gateway, AuthToken("".into()))); - let character_loop = character_mainloop(*char_state, elseware::login::character::CHARACTER_PORT, elseware::login::login::COMMUNICATION_PORT); - - let thread_entity_gateway = entity_gateway.clone(); - info!("[ship] starting server"); - let ship_state = Box::new(ShipServerStateBuilder::default() - .name("US/Sona-Nyl".into()) - .ip(Ipv4Addr::new(127,0,0,1)) - .port(elseware::ship::ship::SHIP_PORT) - .gateway(thread_entity_gateway) - .build()); - let ship_loop = ship_mainloop(*ship_state, elseware::ship::ship::SHIP_PORT, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT); - - let thread_entity_gateway = entity_gateway.clone(); - let ship_state = Box::new(ShipServerStateBuilder::default() - .name("EU/Dylath-Leen".into()) - .ip(Ipv4Addr::new(127,0,0,1)) - .port(elseware::ship::ship::SHIP_PORT+2000) - .gateway(thread_entity_gateway) - .build()); - let ship_loop2 = ship_mainloop(*ship_state, elseware::ship::ship::SHIP_PORT+2000, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT); - - let thread_entity_gateway = entity_gateway.clone(); - let ship_state = Box::new(ShipServerStateBuilder::default() - .name("JP/Thalarion".into()) - .ip(Ipv4Addr::new(127,0,0,1)) - .port(elseware::ship::ship::SHIP_PORT+3000) - .gateway(thread_entity_gateway) - .build()); - let ship_loop3 = ship_mainloop(*ship_state, elseware::ship::ship::SHIP_PORT+3000, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT); - - futures::future::join_all(vec![patch_loop, login_loop, character_loop, ship_loop, ship_loop2, ship_loop3]).await; - */ - info!("[patch] starting server"); let patch_config = load_config(); let patch_motd = load_motd(); @@ -391,15 +342,13 @@ fn main() { }); info!("[auth] starting server"); - let auth_entity_gateway = entity_gateway.clone(); - let login_state = LoginServerState::new(auth_entity_gateway, "127.0.0.1".parse().unwrap()); + let login_state = LoginServerState::new(entity_gateway.clone(), "127.0.0.1".parse().unwrap()); let login_loop = async_std::task::spawn(async move { elseware::common::mainloop::run_server(login_state, elseware::login::login::LOGIN_PORT).await; }); info!("[character] starting server"); - let character_entity_gateway = entity_gateway.clone(); - let char_state = CharacterServerState::new(character_entity_gateway, AuthToken("".into())); + let char_state = CharacterServerState::new(entity_gateway.clone(), AuthToken("".into())); let sub_char_state = char_state.clone(); let character_loop = async_std::task::spawn(async move { elseware::common::mainloop::run_server(sub_char_state, elseware::login::character::CHARACTER_PORT).await; @@ -409,66 +358,55 @@ fn main() { let inter_character_loop = async_std::task::spawn(async move { elseware::common::mainloop::run_interserver_listen(sub_char_state, elseware::login::login::COMMUNICATION_PORT).await; }); - /* - let inter_character_loop_recv = async_std::task::spawn(|| async { - crate::common::mainloop::run_interserver_receiver(char_state, elseware::login::character::COMMUNICATION_PORT).await - }); - let inter_character_loop_send = async_std::task::spawn(|| async { - crate::common::mainloop::run_interserver_sender(char_state, interserver_rx).await - */ - let ship_entity_gateway = entity_gateway.clone(); - info!("[ship] starting server"); - - //let (interserver_tx, interserver_rx) = async_std::channel::unbounded(); -/* + info!("[ship] starting servers"); let ship_state = ShipServerStateBuilder::default() .name("US/Sona-Nyl".into()) .ip(Ipv4Addr::new(127,0,0,1)) .port(elseware::ship::ship::SHIP_PORT) - .gateway(thread_entity_gateway) - .interserver_sender(|msg| async move { - interserver_tx.send(msg).await - }) + .gateway(entity_gateway.clone()) .build(); let sub_ship_state = ship_state.clone(); - let ship_loop = async_std::task::spawn(|| async { - crate::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT); + let ship_loop1 = async_std::task::spawn(async move { + elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT).await; }); - /* - /*, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT*/ - let inter_ship_loop = async_std::task::spawn(|| async { - crate::common::mainloop::run_interserver_receiver(ship_state, elseware::login::login::COMMUNICATION_PORT); + let sub_ship_state = ship_state.clone(); + let inter_ship_loop1 = async_std::task::spawn(async move { + elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT).await; }); - */ - let ship_entity_gateway = entity_gateway.clone(); - let ship_state = Box::new(ShipServerStateBuilder::default() + let ship_state = ShipServerStateBuilder::default() .name("EU/Dylath-Leen".into()) .ip(Ipv4Addr::new(127,0,0,1)) - .port(elseware::ship::ship::SHIP_PORT+2000) - .gateway(thread_entity_gateway) - .build()); + .port(elseware::ship::ship::SHIP_PORT+200) + .gateway(entity_gateway.clone()) + .build(); let sub_ship_state = ship_state.clone(); - let ship_loop2 = async_std::task::spawn(|| async { - crate::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT); + let ship_loop2 = async_std::task::spawn(async move { + elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT+2000).await; + }); + let sub_ship_state = ship_state.clone(); + let inter_ship_loop2 = async_std::task::spawn(async move { + elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT).await; }); - let thread_entity_gateway = entity_gateway.clone(); - let ship_state = Box::new(ShipServerStateBuilder::default() + let ship_state = ShipServerStateBuilder::default() .name("JP/Thalarion".into()) .ip(Ipv4Addr::new(127,0,0,1)) .port(elseware::ship::ship::SHIP_PORT+3000) - .gateway(thread_entity_gateway) - .build()); + .gateway(entity_gateway.clone()) + .build(); let sub_ship_state = ship_state.clone(); - let ship_loop3 = async_std::task::spawn(|| async { - crate::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT); + let ship_loop3 = async_std::task::spawn(async move { + elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT+3000).await; + }); + let sub_ship_state = ship_state.clone(); + let inter_ship_loop3 = async_std::task::spawn(async move { + elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT).await; }); - futures::future::join_all(vec![patch_loop, login_loop, character_loop, ship_loop, ship_loop2, ship_loop3]).await; - */ - futures::future::join_all(vec![patch_loop, login_loop, character_loop, inter_character_loop]).await; - + futures::future::join_all(vec![patch_loop, login_loop, character_loop, inter_character_loop, + ship_loop1, ship_loop2, ship_loop3, + inter_ship_loop1, inter_ship_loop2, inter_ship_loop3]).await; }); } diff --git a/src/bin/patch.rs b/src/bin/patch.rs index f6cf2bc..e7304d8 100644 --- a/src/bin/patch.rs +++ b/src/bin/patch.rs @@ -1,18 +1,18 @@ use elseware::patch::patch::{PatchServerState, generate_patch_tree, load_config_env, load_motd}; use log::{info}; -//use elseware::common::mainloop::patch_mainloop; fn main() { - /* info!("[patch] starting server"); let patch_config = load_config_env(); let patch_motd = load_motd(); let (patch_file_tree, patch_file_lookup) = generate_patch_tree(patch_config.path.as_str()); let patch_state = PatchServerState::new(patch_file_tree, patch_file_lookup, patch_motd); - let patch_loop = patch_mainloop(patch_state, patch_config.port); + + let patch_loop = async_std::task::spawn(async move { + elseware::common::mainloop::run_server(patch_state, patch_config.port).await; + }); async_std::task::block_on(async move { patch_loop.await }); - */ } diff --git a/src/bin/ship.rs b/src/bin/ship.rs index 29bbab3..ff1ccc6 100644 --- a/src/bin/ship.rs +++ b/src/bin/ship.rs @@ -1,11 +1,9 @@ use log::{info}; -//use elseware::entity::gateway::postgres::PostgresGateway; -//use elseware::ship::ship::ShipServerStateBuilder; -//use elseware::common::mainloop::ship_mainloop; -//use elseware::common::interserver::AuthToken; +use elseware::entity::gateway::postgres::PostgresGateway; +use elseware::ship::ship::ShipServerStateBuilder; +use elseware::common::interserver::AuthToken; fn main() { - /* let colors = fern::colors::ColoredLevelConfig::new() .error(fern::colors::Color::Red) .warn(fern::colors::Color::Yellow) @@ -38,6 +36,7 @@ fn main() { let shipgate_token = std::env::var("SHIPGATE_TOKEN").unwrap(); let ship_name = std::env::var("SHIP_NAME").unwrap().parse().unwrap(); let ip = std::env::var("SELF_IP").unwrap().parse().unwrap(); + let ship_state = ShipServerStateBuilder::default() .name(ship_name) .ip(ip) @@ -47,11 +46,17 @@ fn main() { .build(); let shipgate_ip = std::env::var("SHIPGATE_IP").unwrap().parse().unwrap(); - let ship_loop = ship_mainloop(ship_state, elseware::ship::ship::SHIP_PORT, shipgate_ip, elseware::login::login::COMMUNICATION_PORT); - + + let sub_ship_state = ship_state.clone(); + let ship_loop = async_std::task::spawn(async move { + elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT).await; + }); + let inter_ship_loop = async_std::task::spawn(async move { + elseware::common::mainloop::run_interserver_connect(ship_state, shipgate_ip, elseware::login::login::COMMUNICATION_PORT).await; + }); + info!("[auth/character] starting server"); async_std::task::block_on(async move { - ship_loop.await + futures::future::join_all(vec![ship_loop, inter_ship_loop]).await; }); - */ } From 9843274bd8373d50b819a842f8e5da772916f702 Mon Sep 17 00:00:00 2001 From: jake Date: Tue, 18 Oct 2022 16:23:32 -0600 Subject: [PATCH 5/9] fix character server/interserver communication --- src/ship/ship.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 18ab8b2..77f762d 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -923,7 +923,7 @@ impl InterserverActor for ShipServerState { Vec::new() } - fn set_sender(&mut self, _server_id: ServerId, sender: channel::Sender) { + async fn set_sender(&mut self, _server_id: ServerId, sender: channel::Sender) { self.shipgate_sender = Some(sender); } } From 4b1ded6f7d253d131e00cbe3c5484d8294e3cc3a Mon Sep 17 00:00:00 2001 From: jake Date: Tue, 18 Oct 2022 16:26:08 -0600 Subject: [PATCH 6/9] clean up new mainloop stuff --- src/common/interserver.rs | 3 +- src/common/mainloop/client.rs | 344 ++++++++---------- src/common/mainloop/interserver.rs | 341 ++++++++---------- src/common/mainloop/mod.rs | 546 +---------------------------- 4 files changed, 303 insertions(+), 931 deletions(-) diff --git a/src/common/interserver.rs b/src/common/interserver.rs index ac37d65..a645f95 100644 --- a/src/common/interserver.rs +++ b/src/common/interserver.rs @@ -56,6 +56,5 @@ pub trait InterserverActor: Clone { async fn on_connect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)>; async fn on_action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result, Self::Error>; async fn on_disconnect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)>; - //fn set_sender(&mut self, server_id: ServerId, func: Arc Box>>>); - fn set_sender(&mut self, server_id: ServerId, tx: channel::Sender); + async fn set_sender(&mut self, server_id: ServerId, tx: channel::Sender); } diff --git a/src/common/mainloop/client.rs b/src/common/mainloop/client.rs index 456fb82..6cf7de4 100644 --- a/src/common/mainloop/client.rs +++ b/src/common/mainloop/client.rs @@ -1,10 +1,10 @@ -use std::pin::pin; +use std::collections::HashMap; +use std::fmt::Debug; +use async_std::channel; +use async_std::io::prelude::{ReadExt, WriteExt}; +use async_std::sync::{Arc, RwLock}; use futures::future::Future; use log::{trace, info, warn}; -use async_std::sync::{Arc, Mutex}; -use async_std::io::prelude::{ReadExt, WriteExt}; -use std::collections::HashMap; -use std::pin::Pin; use libpso::crypto::{PSOCipher, NullCipher, CipherError}; use libpso::PacketParseError; @@ -42,7 +42,6 @@ impl From for NetworkError { pub struct PacketReceiver { socket: async_std::net::TcpStream, - //cipher: Arc>>, cipher: C, recv_buffer: Vec, incoming_data: Vec, @@ -115,209 +114,160 @@ impl PacketReceiver { Ok(result) } } -/* -async fn send_pkt(socket: Arc, - cipher: Arc>>, pkt: S) - -> Result<(), NetworkError> +async fn recv_loop(mut state: STATE, + socket: async_std::net::TcpStream, + client_id: ClientId, + cipher: C, + clients: Arc>>>) +where + STATE: ServerState + Send, + S: SendServerPacket + Debug + Send, + R: RecvServerPacket + Debug + Send, + C: PSOCipher + Send, + E: std::fmt::Debug + Send, +{ + let mut pkt_receiver = PacketReceiver::new(socket, cipher); + loop { + match pkt_receiver.recv_pkts::().await { + Ok(pkts) => { + for pkt in pkts { + info!("[recv from {:?}] {:#?}", client_id, pkt); + match state.handle(client_id, pkt).await { + Ok(response) => { + for resp in response { + clients + .read() + .await + .get(&resp.0) + .unwrap() + .send(resp.1) + .await + .unwrap(); + } + }, + Err(err) => { + warn!("[client recv {:?}] error {:?} ", client_id, err); + } + } + } + }, + Err(err) => { + match err { + NetworkError::ClientDisconnected => { + info!("[client recv {:?}] disconnected", client_id); + for pkt in state.on_disconnect(client_id).await.unwrap() { + clients + .read() + .await + .get(&pkt.0) + .unwrap() + .send(pkt.1) + .await + .unwrap(); + } + clients + .write() + .await + .remove(&client_id); + break; + } + _ => { + warn!("[client {:?} recv error] {:?}", client_id, err); + } + } + } + } + } +} + + +async fn send_pkt(socket: &mut async_std::net::TcpStream, + cipher: &mut C, + pkt: &S) + -> Result<(), NetworkError> +where + S: SendServerPacket + std::fmt::Debug, + C: PSOCipher, { let buf = pkt.as_bytes(); trace!("[send buf] {:?}", buf); - let cbuf = cipher.lock().await.encrypt(&buf)?; - let mut ssock = &*socket; - ssock.write_all(&cbuf).await?; + let cbuf = cipher.encrypt(&buf)?; + socket.write_all(&cbuf).await?; Ok(()) } - -enum ClientAction { - NewClient(ClientId, async_std::channel::Sender), - Packet(ClientId, R), - Disconnect(ClientId), -} - -enum ServerStateAction { - Cipher(Box, Box), - Packet(S), - Disconnect, -} - -fn client_recv_loop(client_id: ClientId, - socket: Arc, - cipher: Arc>>, - server_sender: async_std::channel::Sender, R>>, - client_sender: async_std::channel::Sender>) +async fn send_loop(mut socket: async_std::net::TcpStream, client_id: ClientId, mut cipher: C, packet_queue: channel::Receiver) where - S: SendServerPacket + std::fmt::Debug + Send + 'static, - R: RecvServerPacket + std::fmt::Debug + Send + 'static, + S: SendServerPacket + std::fmt::Debug, + C: PSOCipher, { - async_std::task::spawn(async move { - server_sender.send(ClientAction::NewClient(client_id, client_sender)).await.unwrap(); - /* - let mut pkt_receiver = PacketReceiver::new(*socket, cipher); + loop { + match packet_queue.recv().await { + Ok(pkt) => { + if let Err(err) = send_pkt(&mut socket, &mut cipher, &pkt).await { + warn!("error sending pkt {:#?} to {:?} {:?}", pkt, client_id, err); + } + }, + Err(err) => { + info!("send to {:?} failed: {:?}", client_id, err); + break; + } + } + } +} - loop { - match pkt_receiver.recv_pkts().await { - Ok(pkts) => { - for pkt in pkts { - info!("[recv from {:?}] {:#?}", client_id, pkt); - server_sender.send(ClientAction::Packet(client_id, pkt)).await.unwrap(); - } +pub async fn run_server(mut state: STATE, port: u16) +where + STATE: ServerState + Send + 'static, + S: SendServerPacket + std::fmt::Debug + Send + 'static, + R: RecvServerPacket + std::fmt::Debug + Send, + C: PSOCipher + Send + 'static, + E: std::fmt::Debug + Send, +{ + let listener = async_std::net::TcpListener::bind(&std::net::SocketAddr::from((std::net::Ipv4Addr::new(0,0,0,0), port))).await.unwrap(); + let mut id = 0; + + let clients = Arc::new(RwLock::new(HashMap::new())); + + loop { + let (mut socket, addr) = listener.accept().await.unwrap(); + id += 1; + + let client_id = crate::common::serverstate::ClientId(id); + info!("new client {:?} {:?} {:?}", client_id, socket, addr); + + let (client_tx, client_rx) = async_std::channel::unbounded(); + + clients + .write() + .await + .insert(client_id, client_tx.clone()); + + let mut cipher_in: Option = None; + let mut cipher_out: Option = None; + + for action in state.on_connect(client_id).await.unwrap() { + match action { + OnConnect::Cipher(cin, cout) => { + cipher_in = Some(cin); + cipher_out = Some(cout); }, - Err(err) => { - match err { - NetworkError::ClientDisconnected => { - trace!("[client disconnected] {:?}", client_id); - server_sender.send(ClientAction::Disconnect(client_id)).await.unwrap(); - break; - } - _ => { - warn!("[client {:?} recv error] {:?}", client_id, err); - } - } + OnConnect::Packet(pkt) => { + send_pkt(&mut socket, &mut NullCipher {}, &pkt).await.unwrap(); } } } - */ - }); + + let rstate = state.clone(); + let rsocket = socket.clone(); + let rclients = clients.clone(); + async_std::task::spawn(async move { + recv_loop(rstate, rsocket, client_id, cipher_in.unwrap(), rclients).await + }); + + async_std::task::spawn(async move { + send_loop(socket, client_id, cipher_out.unwrap(), client_rx).await + }); + } } - -fn client_send_loop(client_id: ClientId, - socket: Arc, - cipher_in: Arc>>, - cipher_out: Arc>>, - client_receiver: async_std::channel::Receiver>) -where - S: SendServerPacket + std::fmt::Debug + Send + 'static, -{ - async_std::task::spawn(async move { - loop { - let action = client_receiver.recv().await.unwrap(); - match action { - ServerStateAction::Cipher(inc, outc) => { - *cipher_in.lock().await = inc; - *cipher_out.lock().await = outc; - } - ServerStateAction::Packet(pkt) => { - info!("[send to {:?}] {:#?}", client_id, pkt); - if let Err(err) = send_pkt(socket.clone(), cipher_out.clone(), pkt).await { - warn!("[client {:?} send error ] {:?}", client_id, err); - } - }, - ServerStateAction::Disconnect => { - break; - } - }; - } - }); -} - -fn state_client_loop(state: Arc>, - server_state_receiver: async_std::channel::Receiver, R>>) where - STATE: ServerState + Send + 'static, - S: SendServerPacket + std::fmt::Debug + Send + 'static, - R: RecvServerPacket + std::fmt::Debug + Send + 'static, - E: std::fmt::Debug + Send, -{ - async_std::task::spawn(async move { - let mut clients = HashMap::new(); - - loop { - let action = server_state_receiver.recv().await.unwrap(); - let mut state = state.lock().await; - - match action { - ClientAction::NewClient(client_id, sender) => { - let actions = state.on_connect(client_id).await; - match actions { - Ok(actions) => { - for action in actions { - match action { - OnConnect::Cipher((inc, outc)) => { - sender.send(ServerStateAction::Cipher(inc, outc)).await.unwrap(); - }, - OnConnect::Packet(pkt) => { - sender.send(ServerStateAction::Packet(pkt)).await.unwrap(); - } - } - } - }, - Err(err) => { - warn!("[client {:?} state on_connect error] {:?}", client_id, err); - } - } - clients.insert(client_id, sender); - }, - ClientAction::Packet(client_id, pkt) => { - let pkts = state.handle(client_id, &pkt).await; - match pkts { - Ok(pkts) => { - for (client_id, pkt) in pkts { - if let Some(client) = clients.get_mut(&client_id) { - client.send(ServerStateAction::Packet(pkt)).await.unwrap(); - } - } - }, - Err(err) => { - warn!("[client {:?} state handler error] {:?}", client_id, err); - } - } - }, - ClientAction::Disconnect(client_id) => { - let pkts = state.on_disconnect(client_id).await; - match pkts { - Ok(pkts) => { - for (client_id, pkt) in pkts { - if let Some(client) = clients.get_mut(&client_id) { - client.send(ServerStateAction::Packet(pkt)).await.unwrap(); - } - } - - if let Some(client) = clients.get_mut(&client_id) { - client.send(ServerStateAction::Disconnect).await.unwrap(); - } - } - Err(err) => { - warn!("[client {:?} state on_disconnect error] {:?}", client_id, err); - } - } - } - } - } - }); -} - - -pub fn client_accept_mainloop(state: Arc>, client_port: u16) -> Pin>> -where - STATE: ServerState + Send + 'static, - S: SendServerPacket + std::fmt::Debug + Send + Sync + 'static, - R: RecvServerPacket + std::fmt::Debug + Send + Sync + 'static, - E: std::fmt::Debug + Send, -{ - Box::pin(async_std::task::spawn(async move { - let listener = async_std::net::TcpListener::bind(&std::net::SocketAddr::from((std::net::Ipv4Addr::new(0,0,0,0), client_port))).await.unwrap(); - let mut id = 0; - - let (server_state_sender, server_state_receiver) = async_std::channel::bounded(1024); - state_client_loop(state, server_state_receiver); - - loop { - let (sock, addr) = listener.accept().await.unwrap(); - id += 1; - let client_id = crate::common::serverstate::ClientId(id); - - info!("new client {:?} {:?} {:?}", client_id, sock, addr); - - let (client_sender, client_receiver) = async_std::channel::bounded(64); - let socket = Arc::new(sock); - let cipher_in: Arc>> = Arc::new(Mutex::new(Box::new(NullCipher {}))); - let cipher_out: Arc>> = Arc::new(Mutex::new(Box::new(NullCipher {}))); - - client_recv_loop(client_id, socket.clone(), cipher_in.clone(), server_state_sender.clone(), client_sender); - client_send_loop(client_id, socket.clone(), cipher_in.clone(), cipher_out.clone(), client_receiver); - } - })) -} - -*/ diff --git a/src/common/mainloop/interserver.rs b/src/common/mainloop/interserver.rs index aab00bb..dbe940d 100644 --- a/src/common/mainloop/interserver.rs +++ b/src/common/mainloop/interserver.rs @@ -2,7 +2,7 @@ use std::time::Duration; use std::pin::Pin; use futures::future::Future; use log::{info, warn}; -use async_std::sync::{Arc, Mutex}; +use async_std::sync::{Arc, RwLock}; use async_std::io::prelude::{ReadExt, WriteExt}; use std::collections::HashMap; use serde::Serialize; @@ -17,6 +17,8 @@ use crate::login::character::CharacterServerState; use crate::entity::gateway::entitygateway::EntityGateway; use async_std::channel; +use std::fmt::Debug; + #[derive(Debug)] enum MessageReceiverError { @@ -37,7 +39,7 @@ impl MessageReceiver { } } - async fn recv(&mut self) -> Result { + async fn recv(&mut self) -> Result { let mut size_buf = [0u8; 4]; self.socket.read_exact(&mut size_buf).await.map_err(|_| MessageReceiverError::Disconnected)?; let size = u32::from_le_bytes(size_buf) as usize; @@ -50,219 +52,182 @@ impl MessageReceiver { Ok(msg) } } -/* -#[derive(Debug)] -enum InterserverInputAction { - NewConnection(ServerId, async_std::channel::Sender), - Message(ServerId, R), - Disconnect(ServerId), -} - -async fn interserver_state_loop(state: Arc>, action_receiver: async_std::channel::Receiver>) +async fn interserver_recv_loop(mut state: STATE, server_id: ServerId, socket: async_std::net::TcpStream, ships: Arc>>>) where - A: InterserverActor + Send + 'static, - S: Serialize + Send + 'static, - R: DeserializeOwned + Send + 'static, + STATE: InterserverActor + Send, + S: serde::Serialize + Debug + Send, + R: serde::de::DeserializeOwned + Debug + Send, + E: Debug + Send, { - async_std::task::spawn(async move { - let mut ships = HashMap::new(); + let mut msg_receiver = MessageReceiver::new(socket); - loop { - info!("interserver loop"); - let action = match action_receiver.recv().await { - Ok(action) => action, - Err(err) => { - warn!("error in iterserver state loop {:?}", err); - continue; - } - }; - let mut state = state.lock().await; - - match action { - InterserverInputAction::NewConnection(server_id, ship_action_sender) => { - ships.insert(server_id, ship_action_sender); - for (server, action) in state.on_connect(server_id).await { - if let Some(sender) = ships.get_mut(&server) { - sender.send(action).await.unwrap(); - } - } - }, - InterserverInputAction::Message(server_id, message) => { - let actions = state.action(server_id, message).await; - match actions { - Ok(actions) => { - for (server, action) in actions{ - if let Some(sender) = ships.get_mut(&server) { - sender.send(action).await.unwrap(); - } - } - }, - Err(err) => { - warn!("[server {:?} state handler error] {:?}", server_id, err); - } - } - }, - InterserverInputAction::Disconnect(server_id) => { - let actions = state.on_disconnect(server_id).await; - ships.remove(&server_id); - for (server, action) in actions { - if let Some(sender) = ships.get_mut(&server) { - sender.send(action).await.unwrap(); + loop { + match msg_receiver.recv::().await { + Ok(msg) => { + info!("[interserver recv {:?}] {:?}", server_id, msg); + match state.on_action(server_id, msg).await { + Ok(response) => { + for resp in response { + ships + .read() + .await + .get(&resp.0) + .unwrap() + .send(resp.1) + .await + .unwrap(); } + }, + Err(err) => { + warn!("[interserver recv {:?}] error {:?}", server_id, err); } } - } - } - }); -} - -async fn login_recv_loop(server_id: ServerId, - socket: async_std::net::TcpStream, - state_loop_sender: async_std::channel::Sender>, - output_loop_sender: async_std::channel::Sender) -where - S: Serialize + std::fmt::Debug + Send + 'static, - R: DeserializeOwned + std::fmt::Debug + Send + 'static, -{ - async_std::task::spawn(async move { - state_loop_sender.send(InterserverInputAction::NewConnection(server_id, output_loop_sender)).await.unwrap(); - let mut msg_receiver = MessageReceiver::new(socket); - - loop { - info!("login recv loop"); - match msg_receiver.recv().await { - Ok(msg) => { - info!("[login recv loop msg] {:?}", msg); - state_loop_sender.send(InterserverInputAction::Message(server_id, msg)).await.unwrap(); - }, - Err(err) => { - if let MessageReceiverError::Disconnected = err { - info!("[login recv loop disconnect] {:?}", server_id); - state_loop_sender.send(InterserverInputAction::Disconnect(server_id)).await.unwrap(); - break; - } - info!("[login recv loop err] {:?}", err); - } - } - } - }); -} - -async fn interserver_send_loop(server_id: ServerId, - mut socket: async_std::net::TcpStream, - output_loop_receiver: async_std::channel::Receiver) -where - S: Serialize + std::fmt::Debug + Send + 'static, -{ - async_std::task::spawn(async move { - loop { - info!("login send loop"); - match output_loop_receiver.recv().await { - Ok(msg) => { - let payload = serde_json::to_string(&msg); - if let Ok(payload) = payload { - let len_bytes = u32::to_le_bytes(payload.len() as u32); - - if let Err(err) = socket.write_all(&len_bytes).await { - warn!("interserver send failed: {:?}", err); - break; - } - if let Err(err) = socket.write_all(payload.as_bytes()).await { - warn!("intserserver send failed: {:?}", err); - break; + }, + Err(err) => { + if let MessageReceiverError::Disconnected = err { + info!("[interserver recv {:?}] disconnected", server_id); + for (_, _sender) in ships.read().await.iter() { + for pkt in state.on_disconnect(server_id).await { + ships + .read() + .await + .get(&pkt.0) + .unwrap() + .send(pkt.1) + .await + .unwrap(); } } - }, - Err(err) => { - warn!("error in send_loop: {:?}, {:?}", server_id, err); + ships + .write() + .await + .remove(&server_id); break; } + info!("[interserver recv {:?}] error {:?}", server_id, err); } } - }); + } } +async fn interserver_send_loop(server_id: ServerId, mut socket: async_std::net::TcpStream, to_send: channel::Receiver) +where + S: serde::Serialize + std::fmt::Debug, +{ + loop { + let msg = to_send.recv().await.unwrap(); + let payload = serde_json::to_string(&msg); - -pub fn login_listen_mainloop(state: Arc>>, port: u16) -> Pin>> { - Box::pin(async_std::task::spawn(async move { - let listener = async_std::net::TcpListener::bind(&std::net::SocketAddr::from((std::net::Ipv4Addr::new(0,0,0,0), port))).await.unwrap(); - let mut id = 0; - - let (server_state_sender, server_state_receiver) = async_std::channel::bounded(1024); - interserver_state_loop(state.clone(), server_state_receiver).await; - - loop { - let (socket, addr) = listener.accept().await.unwrap(); - info!("new ship server: {:?} {:?}", socket, addr); - - id += 1; - let server_id = crate::common::interserver::ServerId(id); - let (client_sender, client_receiver) = async_std::channel::bounded(64); - - { - let mut state = state.lock().await; - let local_sender = client_sender.clone(); - state.set_sender(server_id, Box::new(move |message| { - async_std::task::block_on(local_sender.send(message)).unwrap(); - })) + if let Ok(payload) = payload { + let len_bytes = u32::to_le_bytes(payload.len() as u32); + if let Err(err) = socket.write_all(&len_bytes).await { + warn!("[interserver send {:?}] failed: {:?}", server_id, err); + break; + } + if let Err(err) = socket.write_all(payload.as_bytes()).await { + warn!("[interserver send {:?}] failed: {:?}", server_id, err); + break; } - - login_recv_loop(server_id, socket.clone(), server_state_sender.clone(), client_sender).await; - interserver_send_loop(server_id, socket.clone(), client_receiver).await; } - })) + } } -*/ -/* -pub fn ship_connect_mainloop(state: Arc>>, ip: std::net::Ipv4Addr, port: u16) -> Pin>> { - Box::pin(async_std::task::spawn(async move { - let mut id = 0; - let (server_state_sender, server_state_receiver) = async_std::channel::bounded(1024); +pub async fn run_interserver_listen(mut state: STATE, port: u16) +where + STATE: InterserverActor + Send + 'static, + S: serde::Serialize + Debug + Send + 'static, + R: serde::de::DeserializeOwned + Debug + Send, + E: Debug + Send, +{ + let listener = async_std::net::TcpListener::bind(&std::net::SocketAddr::from((std::net::Ipv4Addr::new(0,0,0,0), port))).await.unwrap(); + let mut id = 0; + let ships = Arc::new(RwLock::new(HashMap::new())); - interserver_state_loop(state.clone(), server_state_receiver).await; + loop { + let (socket, addr) = listener.accept().await.unwrap(); + info!("[interserver listen] new server: {:?} {:?}", socket, addr); - loop { - info!("trying to connect to loginserv"); - let socket = match async_std::net::TcpStream::connect((ip, port)).await { - Ok(socket) => socket, - Err(err) => { - info!("err trying to connect to loginserv {:?}", err); - async_std::task::sleep(Duration::from_secs(10)).await; - continue; - } - }; - id += 1; - let server_id = crate::common::interserver::ServerId(id); - info!("found loginserv: {:?} {:?}", server_id, socket); - let (client_sender, client_receiver) = async_std::channel::bounded(64); + id += 1; + let server_id = crate::common::interserver::ServerId(id); + let (client_tx, client_rx) = async_std::channel::unbounded(); + state.set_sender(server_id, client_tx.clone()).await; - { - let mut state = state.lock().await; - let local_sender = client_sender.clone(); - state.set_sender(Box::new(move |message| { - async_std::task::block_on(local_sender.send(message)).unwrap(); - })) + ships + .write() + .await + .insert(server_id, client_tx.clone()); + + for msg in state.on_connect(server_id).await { + if let Some(ship_sender) = ships.read().await.get(&msg.0) { + ship_sender.send(msg.1).await.unwrap(); } + } - login_recv_loop(server_id, socket.clone(), server_state_sender.clone(), client_sender).await; - interserver_send_loop(server_id, socket.clone(), client_receiver).await; + let rstate = state.clone(); + let rsocket = socket.clone(); + let rships = ships.clone(); + async_std::task::spawn(async move { + interserver_recv_loop(rstate, server_id, rsocket, rships).await; + }); + async_std::task::spawn(async move { + interserver_send_loop(server_id, socket, client_rx).await; + }); + } +} - let mut buf = [0u8; 1]; - loop { - let peek = socket.peek(&mut buf).await; - match peek { - Ok(len) if len == 0 => { - break - }, - _ => { - } +pub async fn run_interserver_connect(mut state: STATE, ip: std::net::Ipv4Addr, port: u16) +where + STATE: InterserverActor + Send + 'static, + S: serde::Serialize + Debug + Send + 'static, + R: serde::de::DeserializeOwned + Debug + Send, + E: Debug + Send, +{ + let mut id = 0; + + loop { + info!("[interserver connect] trying to connect to server"); + let socket = match async_std::net::TcpStream::connect((ip, port)).await { + Ok(socket) => socket, + Err(err) => { + info!("err trying to connect to loginserv {:?}", err); + async_std::task::sleep(std::time::Duration::from_secs(10)).await; + continue; + } + }; + id += 1; + let server_id = crate::common::interserver::ServerId(id); + info!("[interserver connect] found loginserv: {:?} {:?}", server_id, socket); + + let (client_tx, client_rx) = async_std::channel::unbounded(); + state.set_sender(server_id, client_tx.clone()).await; + + for msg in state.on_connect(server_id).await { + client_tx.send(msg.1).await.unwrap(); + } + + let other_server = vec![(server_id, client_tx.clone())].into_iter().collect(); + let rstate = state.clone(); + let rsocket = socket.clone(); + async_std::task::spawn(async move { + interserver_recv_loop(rstate, server_id, rsocket, Arc::new(RwLock::new(other_server))).await; + }); + let ssocket = socket.clone(); + async_std::task::spawn(async move { + interserver_send_loop(server_id, ssocket, client_rx).await; + }); + + let mut buf = [0u8; 1]; + loop { + let peek = socket.peek(&mut buf).await; + match peek { + Ok(len) if len == 0 => { + break + }, + _ => { } } } - })) -} + } -*/ +} diff --git a/src/common/mainloop/mod.rs b/src/common/mainloop/mod.rs index a83375d..d63d682 100644 --- a/src/common/mainloop/mod.rs +++ b/src/common/mainloop/mod.rs @@ -2,547 +2,5 @@ mod client; mod interserver; -use std::collections::HashMap; -use log::{trace, info, warn}; -use std::pin::Pin; -use futures::future::{Future, join_all, FutureExt}; -use async_std::sync::{Arc, Mutex, RwLock}; - -use std::fmt::Debug; - -use async_std::io::prelude::{ReadExt, WriteExt}; -//use crate::common::mainloop::client::client_accept_mainloop; -//use crate::common::mainloop::interserver::{ship_connect_mainloop, login_listen_mainloop}; -pub use crate::common::mainloop::client::NetworkError; -use crate::common::mainloop::client::PacketReceiver; - -use crate::common::serverstate::ClientId; -use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect}; - -use crate::common::interserver::{ServerId, InterserverActor}; - -use crate::patch::patch::PatchServerState; -use crate::login::login::LoginServerState; -use crate::login::character::CharacterServerState; -//use crate::ship::ship::ShipServerState; -use crate::entity::gateway::entitygateway::EntityGateway; - -use libpso::crypto::{PSOCipher, NullCipher, CipherError}; - -use async_std::channel; - - - - -/* -pub fn patch_mainloop(patch_state: PatchServerState, patch_port: u16) -> Pin>> { - let patch_state = Arc::new(Mutex::new(patch_state)); - let client_mainloop = client_accept_mainloop(patch_state, patch_port); - Box::pin(client_mainloop) -} - -pub fn login_mainloop(login_state: LoginServerState, login_port: u16) -> Pin>> { - let login_state = Arc::new(Mutex::new(login_state)); - let client_mainloop = client_accept_mainloop(login_state, login_port); - Box::pin(client_mainloop) -} - -pub fn character_mainloop(character_state: CharacterServerState, character_port: u16, comm_port: u16) -> Pin>> { - let character_state = Arc::new(Mutex::new(character_state)); - let client_mainloop = client_accept_mainloop(character_state.clone(), character_port); - let ship_communication_mainloop = login_listen_mainloop(character_state, comm_port); - Box::pin(join_all(vec![client_mainloop, ship_communication_mainloop]).map(|_| ())) -} - - -pub fn ship_mainloop(ship_state: ShipServerState, ship_port: u16, comm_ip: std::net::Ipv4Addr, comm_port: u16) -> Pin>> { - let ship_state = Arc::new(Mutex::new(ship_state)); - let client_mainloop = client_accept_mainloop(ship_state.clone(), ship_port); - let login_communication_mainloop = ship_connect_mainloop(ship_state, comm_ip, comm_port); - Box::pin(join_all(vec![client_mainloop, login_communication_mainloop]).map(|_| ())) -} -*/ - - -#[derive(Debug)] -enum MessageReceiverError { - //InvalidSize, - InvalidPayload, - //NetworkError(std::io::Error), - Disconnected, -} - -struct MessageReceiver { - socket: async_std::net::TcpStream, -} - -impl MessageReceiver { - fn new(socket: async_std::net::TcpStream) -> MessageReceiver { - MessageReceiver { - socket, - } - } - - async fn recv(&mut self) -> Result { - let mut size_buf = [0u8; 4]; - self.socket.read_exact(&mut size_buf).await.map_err(|_| MessageReceiverError::Disconnected)?; - let size = u32::from_le_bytes(size_buf) as usize; - - let mut payload = vec![0u8; size]; - self.socket.read_exact(&mut payload).await.map_err(|_| MessageReceiverError::Disconnected)?; - let payload = String::from_utf8(payload).map_err(|_| MessageReceiverError::InvalidPayload)?; - - let msg = serde_json::from_str(&payload).map_err(|_| MessageReceiverError::InvalidPayload)?; - Ok(msg) - } -} - - -/* -enum ServerAction { - NewClient(ClientId, channel::Sender), - Packet(ClientId, S), - Disconnect(ClientId), -} -*/ - -async fn recv_loop(mut state: STATE, - socket: async_std::net::TcpStream, - client_id: ClientId, - cipher: C, - clients: Arc>>>) -where - STATE: ServerState + Send, - S: SendServerPacket + Debug + Send, - R: RecvServerPacket + Debug + Send, - C: PSOCipher + Send, - E: std::fmt::Debug + Send, -{ - let mut pkt_receiver = PacketReceiver::new(socket, cipher); - loop { - match pkt_receiver.recv_pkts::().await { - Ok(pkts) => { - for pkt in pkts { - info!("[recv from {:?}] {:#?}", client_id, pkt); - match state.handle(client_id, pkt).await { - Ok(response) => { - for resp in response { - clients - .read() - .await - .get(&resp.0) - .unwrap() - .send(resp.1) - .await; - } - }, - Err(err) => { - warn!("[client recv {:?}] error {:?} ", client_id, err); - } - } - } - }, - Err(err) => { - match err { - NetworkError::ClientDisconnected => { - info!("[client recv {:?}] disconnected", client_id); - for pkt in state.on_disconnect(client_id).await.unwrap() { - clients - .read() - .await - .get(&pkt.0) - .unwrap() - .send(pkt.1) - .await; - } - clients - .write() - .await - .remove(&client_id); - break; - } - _ => { - warn!("[client {:?} recv error] {:?}", client_id, err); - } - } - } - } - } -} - - -async fn send_pkt(socket: &mut async_std::net::TcpStream, - cipher: &mut C, - pkt: &S) - -> Result<(), NetworkError> -where - S: SendServerPacket + std::fmt::Debug, - C: PSOCipher, -{ - let buf = pkt.as_bytes(); - trace!("[send buf] {:?}", buf); - let cbuf = cipher.encrypt(&buf)?; - socket.write_all(&cbuf).await?; - Ok(()) -} - -async fn send_loop(mut socket: async_std::net::TcpStream, client_id: ClientId, mut cipher: C, packet_queue: channel::Receiver) -where - S: SendServerPacket + std::fmt::Debug, - C: PSOCipher, -{ - loop { - let pkt = packet_queue.recv().await.unwrap(); - if let Err(err) = send_pkt(&mut socket, &mut cipher, &pkt).await { - warn!("error sending pkt {:#?} to {:?} {:?}", pkt, client_id, err); - } - } -} - -/* -pub async fn server_multiplex(state: STATE, packet_queue: channel::Receiver>) -where - STATE: ServerState, - S: SendServerPacket + std::fmt::Debug, - R: RecvServerPacket + std::fmt::Debug, - E: std::fmt::Debug, -{ - let mut clients = HashMap::new(); - loop { - let action = packet_queue.recv().await.unwrap(); - - match action { - ServerAction::NewClient(client_id, sender) => { - clients.insert(client_id, sender); - }, - ServerAction::Packet(client_id, pkt) => { - if let Some(sender) = clients.get(&client_id) { - sender.send(pkt).await; - } - }, - ServerAction::Disconnect(client_id) => { - clients.remove(&client_id); - } - } - - } -} -*/ - -pub async fn run_server(mut state: STATE, port: u16) -where - STATE: ServerState + Send + 'static, - S: SendServerPacket + std::fmt::Debug + Send + 'static, - R: RecvServerPacket + std::fmt::Debug + Send, - C: PSOCipher + Send + 'static, - E: std::fmt::Debug + Send, -{ - let listener = async_std::net::TcpListener::bind(&std::net::SocketAddr::from((std::net::Ipv4Addr::new(0,0,0,0), port))).await.unwrap(); - let mut id = 0; - //let (packet_sender, packet_receiver) = async_std::channel::unbounded(); - - let clients = Arc::new(RwLock::new(HashMap::new())); - - //let cstate = state.clone(); - /* - async_std::task::spawn(async move { - server_multiplex(cstate, packet_receiver).await - }); - */ - - loop { - let (mut socket, addr) = listener.accept().await.unwrap(); - id += 1; - - let client_id = crate::common::serverstate::ClientId(id); - info!("new client {:?} {:?} {:?}", client_id, socket, addr); - - let (client_tx, client_rx) = async_std::channel::unbounded(); - //packet_sender.send(ServerAction::NewClient()).await; - - clients - .write() - .await - .insert(client_id, client_tx.clone()); - - let mut cipher_in: Option = None; - let mut cipher_out: Option = None; - - for action in state.on_connect(client_id).await.unwrap() { - match action { - OnConnect::Cipher(cin, cout) => { - cipher_in = Some(cin); - cipher_out = Some(cout); - }, - OnConnect::Packet(pkt) => { - send_pkt(&mut socket, &mut NullCipher {}, &pkt).await; - } - } - } - - let rstate = state.clone(); - let rsocket = socket.clone(); - let rclients = clients.clone(); - async_std::task::spawn(async move { - /* - rstate; - rsocket; - client_id; - cipher_in.unwrap(); - rclients; - */ - //client_tx.send(12).await - recv_loop(rstate, rsocket, client_id, cipher_in.unwrap(), rclients).await - //recv_loop2(rstate, rsocket, client_id, cipher_in.unwrap()).await - }); - - //let sstate = state.clone(); - async_std::task::spawn(async move { - send_loop(socket, client_id, cipher_out.unwrap(), client_rx).await - }); - } -} - -/* -pub async fn listen_interserver(state: STATE, port: u16) -where - STATE: InterserverActor, - S: serde::Serialize, - R: serde::de::DeserializeOwned, -{ - let listener = async_std::net::TcpListener::bind(&std::net::SocketAddr::from((std::net::Ipv4Addr::new(0,0,0,0), port))).await.unwrap(); - let mut id = 0; - - loop { - let (socket, addr) = listener.accept().await.unwrap(); - info!("new interserver connection: {:?} {:?}", socket, addr); - - id += 1; - let server_id = crate::common::interserver::ServerId(id); - } -} - - -pub async fn run_interserver_receiver(state: STATE, ip: std::net::Ipv4Addr, port: u16) -where - STATE: InterserverActor, - S: serde::Serialize, - R: serde::de::DeserializeOwned, -{ - loop { - - } - - -} - -pub async fn run_interserver_sender(state: STATE, to_send: channel::Receiver) -where - STATE: InterserverActor, - S: serde::Serialize, - R: serde::de::DeserializeOwned, -{ - loop { - let msg = to_send.recv().await.unwrap(); - - let response = state.on_action(msg); - - - - - } - -} -*/ - -async fn interserver_recv_loop(mut state: STATE, server_id: ServerId, socket: async_std::net::TcpStream, ships: Arc>>>) -where - STATE: InterserverActor + Send, - S: serde::Serialize + Debug + Send, - R: serde::de::DeserializeOwned + Debug + Send, - E: Debug + Send, -{ - let mut msg_receiver = MessageReceiver::new(socket); - - loop { - match msg_receiver.recv::().await { - Ok(msg) => { - info!("[interserver recv {:?}] {:?}", server_id, msg); - match state.on_action(server_id, msg).await { - Ok(response) => { - for resp in response { - ships - .read() - .await - .get(&resp.0) - .unwrap() - .send(resp.1) - .await; - } - }, - Err(err) => { - warn!("[interserver recv {:?}] error {:?}", server_id, err); - } - } - }, - Err(err) => { - if let MessageReceiverError::Disconnected = err { - info!("[interserver recv {:?}] disconnected", server_id); - for (_, sender) in ships.read().await.iter() { - for pkt in state.on_disconnect(server_id).await { - ships - .read() - .await - .get(&pkt.0) - .unwrap() - .send(pkt.1) - .await; - } - } - ships - .write() - .await - .remove(&server_id); - break; - } - info!("[interserver recv {:?}] error {:?}", server_id, err); - } - } - } -} - -async fn interserver_send_loop(server_id: ServerId, mut socket: async_std::net::TcpStream, to_send: channel::Receiver) -where - S: serde::Serialize + std::fmt::Debug, -{ - loop { - let msg = to_send.recv().await.unwrap(); - let payload = serde_json::to_string(&msg); - - if let Ok(payload) = payload { - let len_bytes = u32::to_le_bytes(payload.len() as u32); - if let Err(err) = socket.write_all(&len_bytes).await { - warn!("[interserver send {:?}] failed: {:?}", server_id, err); - break; - } - if let Err(err) = socket.write_all(payload.as_bytes()).await { - warn!("[interserver send {:?}] failed: {:?}", server_id, err); - break; - } - } - } -} - -pub async fn run_interserver_listen(mut state: STATE, port: u16) -where - STATE: InterserverActor + Send + 'static, - S: serde::Serialize + Debug + Send + 'static, - R: serde::de::DeserializeOwned + Debug + Send, - E: Debug + Send, -{ - let listener = async_std::net::TcpListener::bind(&std::net::SocketAddr::from((std::net::Ipv4Addr::new(0,0,0,0), port))).await.unwrap(); - let mut id = 0; - let ships = Arc::new(RwLock::new(HashMap::new())); - - loop { - let (socket, addr) = listener.accept().await.unwrap(); - info!("[interserver listen] new server: {:?} {:?}", socket, addr); - - id += 1; - let server_id = crate::common::interserver::ServerId(id); - let (client_tx, client_rx) = async_std::channel::unbounded(); - - //let sclient_tx = client_tx.clone(); - /* - state.set_sender(server_id, Arc::new(Box::new(move |msg| { - let sclient_tx = sclient_tx.clone(); - Box::new(async move { - sclient_tx.send(msg).await; - })}))); - */ - state.set_sender(server_id, client_tx.clone()); - - ships - .write() - .await - .insert(server_id, client_tx.clone()); - - for msg in state.on_connect(server_id).await { - if let Some(ship_sender) = ships.read().await.get(&msg.0) { - ship_sender.send(msg.1).await; - } - } - - let rstate = state.clone(); - let rsocket = socket.clone(); - let rships = ships.clone(); - async_std::task::spawn(async move { - interserver_recv_loop(rstate, server_id, rsocket, rships).await; - }); - async_std::task::spawn(async move { - interserver_send_loop(server_id, socket, client_rx).await; - }); - } -} - -pub async fn run_interserver_connect(mut state: STATE, ip: std::net::Ipv4Addr, port: u16) -where - STATE: InterserverActor + Send + 'static, - S: serde::Serialize + Debug + Send + 'static, - R: serde::de::DeserializeOwned + Debug + Send, - E: Debug + Send, -{ - let mut id = 0; - - loop { - info!("[interserver connect] trying to connect to server"); - let socket = match async_std::net::TcpStream::connect((ip, port)).await { - Ok(socket) => socket, - Err(err) => { - info!("err trying to connect to loginserv {:?}", err); - async_std::task::sleep(std::time::Duration::from_secs(10)).await; - continue; - } - }; - id += 1; - let server_id = crate::common::interserver::ServerId(id); - info!("[interserver connect] found loginserv: {:?} {:?}", server_id, socket); - - let (client_tx, client_rx) = async_std::channel::unbounded(); - - state.set_sender(server_id, client_tx.clone()); - /* - let sclient_tx = client_tx.clone(); - state.set_sender(server_id, Arc::new(Box::new(move |msg| { - let sclient_tx = sclient_tx.clone(); - Box::new(async move { - sclient_tx.send(msg).await; - })}))); - */ - - let other_server = vec![(server_id, client_tx.clone())].into_iter().collect(); - - let rstate = state.clone(); - let rsocket = socket.clone(); - async_std::task::spawn(async move { - interserver_recv_loop(rstate, server_id, rsocket, Arc::new(RwLock::new(other_server))).await; - }); - let ssocket = socket.clone(); - async_std::task::spawn(async move { - interserver_send_loop(server_id, ssocket, client_rx).await; - }); - - let mut buf = [0u8; 1]; - loop { - let peek = socket.peek(&mut buf).await; - match peek { - Ok(len) if len == 0 => { - break - }, - _ => { - } - } - } - } - -} +pub use self::client::*; +pub use self::interserver::*; From 192ff967e65afaa7ac0bbb47f526b68780f9d9d1 Mon Sep 17 00:00:00 2001 From: jake Date: Tue, 18 Oct 2022 17:55:47 -0600 Subject: [PATCH 7/9] cleanup this refactored mess --- src/common/interserver.rs | 1 - src/entity/gateway/postgres/models.rs | 18 +- src/login/character.rs | 153 ++++++++------- src/patch/patch.rs | 3 +- src/ship/character.rs | 2 +- src/ship/items/actions.rs | 14 +- src/ship/items/state.rs | 96 +-------- src/ship/map/area.rs | 2 +- src/ship/packet/builder/lobby.rs | 2 +- src/ship/packet/handler/auth.rs | 11 +- src/ship/packet/handler/communication.rs | 2 +- src/ship/packet/handler/direct_message.rs | 42 ++-- src/ship/packet/handler/lobby.rs | 32 +-- src/ship/packet/handler/message.rs | 10 +- src/ship/packet/handler/quest.rs | 134 ++----------- src/ship/packet/handler/room.rs | 60 ++---- src/ship/packet/handler/ship.rs | 2 +- src/ship/packet/handler/trade.rs | 12 +- src/ship/room.rs | 44 +---- src/ship/ship.rs | 225 +++++++--------------- src/ship/shops/armor.rs | 2 +- tests/test_exp_gain.rs | 6 +- 22 files changed, 269 insertions(+), 604 deletions(-) diff --git a/src/common/interserver.rs b/src/common/interserver.rs index a645f95..1f6e0ff 100644 --- a/src/common/interserver.rs +++ b/src/common/interserver.rs @@ -1,5 +1,4 @@ use std::net::Ipv4Addr; -use async_std::sync::Arc; use async_std::channel; use serde::{Serialize, Deserialize}; use serde::de::DeserializeOwned; diff --git a/src/entity/gateway/postgres/models.rs b/src/entity/gateway/postgres/models.rs index cad8959..c7a378b 100644 --- a/src/entity/gateway/postgres/models.rs +++ b/src/entity/gateway/postgres/models.rs @@ -675,18 +675,18 @@ impl From for ItemNote { fn from(other: PgItemNoteDetail) -> ItemNote { match other { PgItemNoteDetail::CharacterCreation{character_id} => ItemNote::CharacterCreation { - character_id: CharacterEntityId(character_id as u32), + character_id: CharacterEntityId(character_id), }, PgItemNoteDetail::EnemyDrop{character_id, map_area, x, y, z} => ItemNote::EnemyDrop { - character_id: CharacterEntityId(character_id as u32), + character_id: CharacterEntityId(character_id), map_area, x,y,z, }, PgItemNoteDetail::Pickup{character_id} => ItemNote::Pickup { - character_id: CharacterEntityId(character_id as u32), + character_id: CharacterEntityId(character_id), }, PgItemNoteDetail::PlayerDrop{character_id, map_area, x, y, z} => ItemNote::PlayerDrop { - character_id: CharacterEntityId(character_id as u32), + character_id: CharacterEntityId(character_id), map_area, x,y,z, }, @@ -699,16 +699,16 @@ impl From for ItemNote { }, PgItemNoteDetail::SoldToShop => ItemNote::SoldToShop, PgItemNoteDetail::Trade {trade_id, character_to, character_from} => ItemNote::Trade { - trade_id: TradeId(trade_id as u32), - character_to: CharacterEntityId(character_to as u32), - character_from: CharacterEntityId(character_from as u32), + trade_id: TradeId(trade_id), + character_to: CharacterEntityId(character_to), + character_from: CharacterEntityId(character_from), }, PgItemNoteDetail::Withdraw{character_id, bank} => ItemNote::Withdraw { - character_id: CharacterEntityId(character_id as u32), + character_id: CharacterEntityId(character_id), bank: BankName(bank), }, PgItemNoteDetail::Deposit{character_id, bank} => ItemNote::Deposit { - character_id: CharacterEntityId(character_id as u32), + character_id: CharacterEntityId(character_id), bank: BankName(bank), }, } diff --git a/src/login/character.rs b/src/login/character.rs index 109681b..87a3c4a 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -2,7 +2,7 @@ use std::io::Read; use std::collections::{BTreeMap, BTreeSet, HashMap}; -use async_std::sync::Arc; +use async_std::sync::{Arc, RwLock}; use async_std::channel; use rand::Rng; @@ -186,16 +186,14 @@ struct ConnectedClient { pub struct CharacterServerState { entity_gateway: EG, param_header: ParamDataHeader, - param_data: Vec, - clients: HashMap, - ships: BTreeMap, - //level_table: CharacterLevelTable, + param_data: Arc>, + clients: Arc>>, + ships: Arc>>, auth_token: AuthToken, - connected_clients: BTreeMap, - authenticated_ships: BTreeSet, - //ship_sender: BTreeMap Box> + Send>>>, - ship_sender: BTreeMap>, + connected_clients: Arc>>, + authenticated_ships: Arc>>, + ship_sender: Arc>>>, } @@ -318,21 +316,21 @@ impl CharacterServerState { CharacterServerState { entity_gateway, param_header, - param_data, - clients: HashMap::new(), - ships: BTreeMap::new(), + param_data: Arc::new(param_data), + clients: Default::default(), + ships: Default::default(), //level_table: CharacterLevelTable::default(), auth_token, - authenticated_ships: BTreeSet::new(), - ship_sender: BTreeMap::new(), - connected_clients: BTreeMap::new(), + authenticated_ships: Default::default(), + ship_sender: Default::default(), + connected_clients: Default::default(), } } async fn validate_login(&mut self, id: ClientId, pkt: &Login) -> Result, anyhow::Error> { match get_login_status(&mut self.entity_gateway, pkt).await { Ok(user) => { - if let Some(connected_client) = self.connected_clients.get(&user.id) { + if let Some(connected_client) = self.connected_clients.read().await.get(&user.id) { if let Some(expires) = connected_client.expires { if expires > chrono::Utc::now() { return Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(AccountStatus::AlreadyOnline, Session::new()))]); @@ -345,11 +343,12 @@ impl CharacterServerState { let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::new()); response.guildcard = user.guildcard; - response.team_id = user.team_id.map_or(0, |ti| ti) as u32; + response.team_id = user.team_id.map_or(0, |ti| ti); - let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; + let mut client = self.clients.write().await; + let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?; - self.connected_clients.insert(user.id, ConnectedClient { + self.connected_clients.write().await.insert(user.id, ConnectedClient { ship_id: None, expires: None, //Some(chrono::Utc::now() + chrono::Duration::minutes(1)), }); @@ -364,9 +363,9 @@ impl CharacterServerState { } } - fn send_ship_list(&mut self, _id: ClientId, _pkt: &Login) -> Result, anyhow::Error> { + async fn send_ship_list(&mut self, _id: ClientId, _pkt: &Login) -> Result, anyhow::Error> { Ok(vec![SendCharacterPacket::Timestamp(Timestamp::new(chrono::Utc::now())), - SendCharacterPacket::ShipList(ShipList::new(self.ships.iter().map(|(i, s)| { + SendCharacterPacket::ShipList(ShipList::new(self.ships.read().await.iter().map(|(i, s)| { ShipListEntry { menu: SHIP_MENU_ID, item: i.0 as u32, @@ -378,7 +377,8 @@ impl CharacterServerState { } async fn get_settings(&mut self, id: ClientId) -> Result, anyhow::Error> { - let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; + let mut client = self.clients.write().await; + let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?; let user = client.user.as_ref().unwrap(); let settings = match self.entity_gateway.get_user_settings_by_user(user).await { @@ -397,7 +397,8 @@ impl CharacterServerState { } async fn char_select(&mut self, id: ClientId, select: &CharSelect) -> Result, anyhow::Error> { - let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; + let mut client = self.clients.write().await; + let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?; if client.characters.is_none() { client.characters = Some(self.entity_gateway.get_characters_by_user(client.user.as_ref().unwrap()).await.map_err(|_| CharacterError::CouldNotLoadCharacters)?); } @@ -443,7 +444,8 @@ impl CharacterServerState { } async fn guildcard_data_header(&mut self, id: ClientId) -> Result, anyhow::Error> { - let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; + let mut client = self.clients.write().await; + let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?; let guildcard_data = self.entity_gateway.get_guild_card_data_by_user(client.user.as_ref().unwrap()).await.map_err(|_| CharacterError::CouldNotLoadGuildcard)?; let bytes = guildcard_data.guildcard.as_bytes(); @@ -454,15 +456,16 @@ impl CharacterServerState { Ok(vec![SendCharacterPacket::GuildcardDataHeader(GuildcardDataHeader::new(bytes.len(), crc.sum32()))]) } - fn guildcard_data_chunk(&mut self, id: ClientId, chunk: u32, again: u32) -> Result, anyhow::Error> { - let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; + async fn guildcard_data_chunk(&mut self, id: ClientId, chunk: u32, again: u32) -> Result, anyhow::Error> { + let mut client = self.clients.write().await; + let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?; Ok(if again != 0 { let start = chunk as usize * GUILD_CARD_CHUNK_SIZE; - let len = std::cmp::min(GUILD_CARD_CHUNK_SIZE, client.guildcard_data_buffer.as_ref().unwrap().len() as usize - start); + let len = std::cmp::min(GUILD_CARD_CHUNK_SIZE, client.guildcard_data_buffer.as_ref().unwrap().len() - start); let end = start + len; - let mut buf = [0u8; GUILD_CARD_CHUNK_SIZE as usize]; - buf[..len as usize].copy_from_slice(&client.guildcard_data_buffer.as_ref().unwrap()[start..end]); + let mut buf = [0u8; GUILD_CARD_CHUNK_SIZE]; + buf[..len].copy_from_slice(&client.guildcard_data_buffer.as_ref().unwrap()[start..end]); vec![SendCharacterPacket::GuildcardDataChunk(Box::new(GuildcardDataChunk::new(chunk, buf, len)))] } else { @@ -471,15 +474,17 @@ impl CharacterServerState { } async fn set_flag(&mut self, id: ClientId, setflag: &SetFlag) -> Result, anyhow::Error> { - let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; + let mut client = self.clients.write().await; + let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?; let mut user = client.user.as_mut().unwrap(); user.flags = setflag.flags; self.entity_gateway.save_user(user).await.unwrap(); Ok(None.into_iter()) } - fn param_data_chunk_request(&mut self, id: ClientId, _request: &ParamDataChunkRequest) -> Result, anyhow::Error> { - let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; + async fn param_data_chunk_request(&mut self, id: ClientId, _request: &ParamDataChunkRequest) -> Result, anyhow::Error> { + let mut client = self.clients.write().await; + let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?; let chunk = client.param_index; client.param_index += 1; @@ -500,7 +505,8 @@ impl CharacterServerState { // TODO: move USERFLAGS over to SessionAction async fn character_preview(&mut self, id: ClientId, preview: &CharacterPreview) -> Result, anyhow::Error> { - let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; + let mut client = self.clients.write().await; + let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?; let mut user = client.user.as_mut().unwrap(); if user.flags == USERFLAG_NEWCHAR { new_character(&mut self.entity_gateway, user, preview).await? @@ -523,26 +529,30 @@ impl CharacterServerState { ]) } - fn select_ship(&mut self, id: ClientId, menuselect: &MenuSelect) -> Result, anyhow::Error> { + async fn select_ship(&mut self, id: ClientId, menuselect: &MenuSelect) -> Result, anyhow::Error> { if menuselect.menu != SHIP_MENU_ID { return Err(CharacterError::InvalidMenuSelection(menuselect.menu, menuselect.item).into()); } - if let Some(client) = self.clients.get(&id) { + if let Some(client) = self.clients.read().await.get(&id) { if let Some(user) = &client.user { - if let Some(cc) = self.connected_clients.get_mut(&user.id) { + if let Some(cc) = self.connected_clients.write().await.get_mut(&user.id) { cc.ship_id = Some(ServerId(menuselect.item as usize)); } } } - let ship = self.ships.get(&ServerId(menuselect.item as usize)) - .ok_or(CharacterError::InvalidMenuSelection(menuselect.menu, menuselect.item))?; + let ship = self.ships.read().await; + let ship = ship.get(&ServerId(menuselect.item as usize)) + .ok_or_else(|| CharacterError::InvalidMenuSelection(menuselect.menu, menuselect.item))?; Ok(vec![SendCharacterPacket::RedirectClient(RedirectClient::new(u32::from_le_bytes(ship.ip.octets()), ship.port))]) } - fn ship_detail(&mut self, menudetail: &MenuDetail) -> Result, anyhow::Error> { - let players = self.connected_clients.iter() + async fn ship_detail(&mut self, menudetail: &MenuDetail) -> Result, anyhow::Error> { + let players = self.connected_clients + .read() + .await + .iter() .filter(|(_, client)| { client.ship_id == Some(ServerId(menudetail.item as usize)) }) @@ -560,7 +570,7 @@ impl ServerState for CharacterServerState { type PacketError = anyhow::Error; async fn on_connect(&mut self, id: ClientId) -> Result>, anyhow::Error> { - self.clients.insert(id, ClientState::new()); + self.clients.write().await.insert(id, ClientState::new()); let mut rng = rand::thread_rng(); @@ -581,7 +591,7 @@ impl ServerState for CharacterServerState { Ok(match pkt { RecvCharacterPacket::Login(login) => { if login.session.action == SessionAction::SelectCharacter { - self.send_ship_list(id, &login)?.into_iter().map(move |pkt| (id, pkt)).collect() + self.send_ship_list(id, &login).await?.into_iter().map(move |pkt| (id, pkt)).collect() } else { self.validate_login(id, &login).await?.into_iter().map(move |pkt| (id, pkt)).collect() @@ -600,7 +610,7 @@ impl ServerState for CharacterServerState { self.guildcard_data_header(id).await?.into_iter().map(move |pkt| (id, pkt)).collect() }, RecvCharacterPacket::GuildcardDataChunkRequest(request) => { - self.guildcard_data_chunk(id, request.chunk, request.again)?.into_iter().map(move |pkt| (id, pkt)).collect() + self.guildcard_data_chunk(id, request.chunk, request.again).await?.into_iter().map(move |pkt| (id, pkt)).collect() }, RecvCharacterPacket::ParamDataRequest(_request) => { vec![SendCharacterPacket::ParamDataHeader(self.param_header.clone())].into_iter().map(move |pkt| (id, pkt)).collect() @@ -609,17 +619,17 @@ impl ServerState for CharacterServerState { self.set_flag(id, &flag).await?.map(move |pkt| (id, pkt)).collect() }, RecvCharacterPacket::ParamDataChunkRequest(request) => { - self.param_data_chunk_request(id, &request)?.into_iter().map(move |pkt| (id, pkt)).collect() + self.param_data_chunk_request(id, &request).await?.into_iter().map(move |pkt| (id, pkt)).collect() }, RecvCharacterPacket::CharacterPreview(preview) => { self.character_preview(id, &preview).await?.into_iter().map(move |pkt| (id, pkt)).collect() }, RecvCharacterPacket::MenuSelect(menuselect) => { - self.select_ship(id, &menuselect)?.into_iter().map(move |pkt| (id, pkt)).collect() + self.select_ship(id, &menuselect).await?.into_iter().map(move |pkt| (id, pkt)).collect() }, RecvCharacterPacket::MenuDetail(menudetail) => { match menudetail.menu { - SHIP_MENU_ID => self.ship_detail(&menudetail)?.into_iter().map(move |pkt| (id, pkt)).collect(), + SHIP_MENU_ID => self.ship_detail(&menudetail).await?.into_iter().map(move |pkt| (id, pkt)).collect(), _ => Vec::new() } } @@ -627,9 +637,9 @@ impl ServerState for CharacterServerState { } async fn on_disconnect(&mut self, id: ClientId) -> Result, anyhow::Error> { - if let Some(client) = self.clients.remove(&id) { + if let Some(client) = self.clients.write().await.remove(&id) { if let Some(user) = client.user { - self.connected_clients.remove(&user.id); + self.connected_clients.write().await.remove(&user.id); } } Ok(Vec::new()) @@ -647,20 +657,25 @@ impl InterserverActor for CharacterServerState { } async fn on_action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result, Self::Error> { + dbg!(&id, &msg); match msg { ShipMessage::Authenticate(auth_token) => { if self.auth_token == auth_token { - self.authenticated_ships.insert(id); + self.authenticated_ships.write().await.insert(id); } Ok(Vec::new()) }, ShipMessage::NewShip(new_ship) => { - if self.authenticated_ships.contains(&id) { - self.ships.insert(id, new_ship); + dbg!("adding ship", &id, &new_ship); + if self.authenticated_ships.read().await.contains(&id) { + self.ships.write().await.insert(id, new_ship); } + dbg!("ship list", &self.authenticated_ships); - let ships = self.ships.iter().map(|(_, s)| s).cloned().collect::>(); + let ships = self.ships.read().await.iter().map(|(_, s)| s).cloned().collect::>(); Ok(self.ships + .read() + .await .iter() .map(|(id, _)| { (*id, LoginMessage::ShipList{ ships: ships.clone() }) @@ -668,8 +683,8 @@ impl InterserverActor for CharacterServerState { .collect()) }, ShipMessage::AddUser(new_user) => { - if self.authenticated_ships.contains(&id) { - self.connected_clients.insert(new_user, ConnectedClient { + if self.authenticated_ships.read().await.contains(&id) { + self.connected_clients.write().await.insert(new_user, ConnectedClient { ship_id: Some(id), expires: None, }); @@ -677,15 +692,18 @@ impl InterserverActor for CharacterServerState { Ok(Vec::new()) }, ShipMessage::RemoveUser(new_user) => { - if self.authenticated_ships.contains(&id) { - self.connected_clients.remove(&new_user); + if self.authenticated_ships.read().await.contains(&id) { + self.connected_clients.write().await.remove(&new_user); } Ok(Vec::new()) }, ShipMessage::RequestShipList => { - if self.authenticated_ships.contains(&id) { + dbg!("request ship list", &self.authenticated_ships); + if self.authenticated_ships.read().await.contains(&id) { Ok(vec![(id, LoginMessage::ShipList { ships: self.ships + .read() + .await .iter() .map(|(_, ship)| { ship @@ -705,18 +723,19 @@ impl InterserverActor for CharacterServerState { } async fn on_disconnect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> { - self.ships.remove(&id); - self.ship_sender.remove(&id); - self.connected_clients = self.connected_clients.clone().into_iter() - .filter(|(_, client)| { + self.ships.write().await.remove(&id); + self.ship_sender.write().await.remove(&id); + self.connected_clients + .write() + .await + .retain(|_, client| { client.ship_id != Some(id) - }) - .collect(); + }); Vec::new() } - fn set_sender(&mut self, server_id: ServerId, sender: channel::Sender) { - self.ship_sender.insert(server_id, sender); + async fn set_sender(&mut self, server_id: ServerId, sender: channel::Sender) { + self.ship_sender.write().await.insert(server_id, sender); } } @@ -845,7 +864,7 @@ mod test { at_character: false, at_ship: false, }); - server.clients.insert(ClientId(5), clientstate); + server.clients.write().await.insert(ClientId(5), clientstate); let send = server.handle(ClientId(5), RecvCharacterPacket::RequestSettings(RequestSettings{})).await.unwrap(); assert!(send.len() == 1); @@ -892,7 +911,7 @@ mod test { }); let mut server = CharacterServerState::new(test_data.clone(), AuthToken("".into())); - server.clients.insert(ClientId(1), fake_user.clone()); + server.clients.write().await.insert(ClientId(1), fake_user.clone()); let mut send = server.handle(ClientId(1), RecvCharacterPacket::SetFlag(SetFlag {flags: 1})).await.unwrap(); assert!(test_data.get_user_by_id(UserAccountId(3)).await.unwrap().flags == 1); send = server.handle(ClientId(1), RecvCharacterPacket::CharacterPreview(CharacterPreview {slot: 1, character: character::SelectScreenCharacter { diff --git a/src/patch/patch.rs b/src/patch/patch.rs index a7b0715..230c5bf 100644 --- a/src/patch/patch.rs +++ b/src/patch/patch.rs @@ -190,9 +190,8 @@ impl ServerState for PatchServerState { .collect() }, RecvPatchPacket::FileInfoReply(pkt) => { - self.patch_file_info.push(pkt.clone()); + self.patch_file_info.push(pkt); Vec::new() - //None.into_iter().map(move |pkt| (id, pkt)) }, RecvPatchPacket::FileInfoListEnd(_pkt) => { let need_update = self.patch_file_info.iter() diff --git a/src/ship/character.rs b/src/ship/character.rs index 454b2c8..348f8ac 100644 --- a/src/ship/character.rs +++ b/src/ship/character.rs @@ -77,7 +77,7 @@ impl<'a> CharacterBytesBuilder<'a> { prop_y: character.appearance.prop_y, config: character.config.as_bytes(), techniques: character.techs.as_bytes(), - meseta: meseta.0 as u32, + meseta: meseta.0, exp: character.exp, ..character::Character::default() } diff --git a/src/ship/items/actions.rs b/src/ship/items/actions.rs index 541077c..e19c4ab 100644 --- a/src/ship/items/actions.rs +++ b/src/ship/items/actions.rs @@ -30,7 +30,7 @@ pub(super) fn take_item_from_floor(character_id: CharacterEntityId, item_id: Cli move |(mut item_state, transaction): (ItemStateProxy<'_>, Box) , _| { Box::pin(async move { let mut floor = item_state.floor(&character_id).await?; - let item = floor.take_item(&item_id).ok_or(ItemStateError::NoFloorItem(item_id))?; + let item = floor.take_item(&item_id).ok_or_else(|| ItemStateError::NoFloorItem(item_id))?; item_state.set_floor(floor).await; Ok(((item_state, transaction), item)) @@ -88,7 +88,7 @@ pub(super) fn take_item_from_inventory(character_id: CharacterEntityId, item_id: move |(mut item_state, mut transaction), _| { Box::pin(async move { let mut inventory = item_state.inventory(&character_id).await?; - let item = inventory.take_item(&item_id, amount).ok_or (ItemStateError::NoFloorItem(item_id))?; + let item = inventory.take_item(&item_id, amount).ok_or_else(|| ItemStateError::NoFloorItem(item_id))?; transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?; item_state.set_inventory(inventory); @@ -238,7 +238,7 @@ pub(super) fn take_item_from_bank(character_id: CharacterEntityId, item_id: Clie move |(mut item_state, mut transaction), _| { Box::pin(async move { let mut bank = item_state.bank(&character_id).await?; - let item = bank.take_item(&item_id, amount).ok_or(ItemStateError::NoBankItem(item_id))?; + let item = bank.take_item(&item_id, amount).ok_or_else(|| ItemStateError::NoBankItem(item_id))?; transaction.gateway().set_character_bank(&character_id, &bank.as_bank_entity(), &bank.name).await?; item_state.set_bank(bank); @@ -407,10 +407,10 @@ pub(super) fn feed_mag_item(character: CharacterEntity, mag_item_id: ClientItemI Box::pin(async move { let mut inventory = item_state.inventory(&character.id).await?; let mag_entity = inventory.get_by_client_id_mut(&mag_item_id) - .ok_or(ItemStateError::InvalidItemId(mag_item_id))? + .ok_or_else(|| ItemStateError::InvalidItemId(mag_item_id))? .item .as_individual_mut() - .ok_or(ItemStateError::NotAMag(mag_item_id))?; + .ok_or_else(|| ItemStateError::NotAMag(mag_item_id))?; let mag_entity_id = mag_entity.entity_id; let mut transaction = tool.with_entity_id(transaction, |mut transaction, entity_id| { @@ -426,13 +426,13 @@ pub(super) fn feed_mag_item(character: CharacterEntity, mag_item_id: ClientItemI let food_tool = tool .item .stacked() - .ok_or(ItemStateError::NotMagFood(tool.item_id))? + .ok_or_else(|| ItemStateError::NotMagFood(tool.item_id))? .tool .tool; let mag_entity = mag_entity .as_mag_mut() - .ok_or(ItemStateError::NotAMag(mag_item_id))?; + .ok_or_else(|| ItemStateError::NotAMag(mag_item_id))?; mag_entity.feed(food_tool); diff --git a/src/ship/items/state.rs b/src/ship/items/state.rs index 5341921..8c95391 100644 --- a/src/ship/items/state.rs +++ b/src/ship/items/state.rs @@ -1,23 +1,19 @@ use std::collections::HashMap; use async_std::sync::{Arc, RwLock}; -use crate::ship::items::ClientItemId; -use crate::entity::item::{ItemEntityId, ItemDetail, ItemEntity, InventoryItemEntity, BankItemEntity, BankName}; - use futures::future::join_all; - - -use crate::ship::location::{AreaClient, RoomId}; -use crate::entity::character::{CharacterEntity, CharacterEntityId}; use crate::entity::gateway::{EntityGateway, GatewayError}; +use crate::entity::character::{CharacterEntity, CharacterEntityId}; +use crate::entity::item::{ItemEntityId, ItemDetail, ItemEntity, InventoryItemEntity, BankItemEntity, BankName}; use crate::entity::item::tool::Tool; use crate::entity::item::weapon::Weapon; use crate::entity::item::mag::Mag; use crate::ship::drops::ItemDrop; - +use crate::ship::items::ClientItemId; use crate::ship::items::inventory::{Inventory, InventoryItem, InventoryItemDetail, InventoryError, InventoryState}; use crate::ship::items::floor::{FloorState, FloorItem, LocalFloor, SharedFloor, FloorType}; use crate::ship::items::bank::{Bank, BankState, BankItem, BankItemDetail, BankError}; +use crate::ship::location::{AreaClient, RoomId}; #[derive(thiserror::Error, Debug)] pub enum ItemStateError { @@ -27,55 +23,38 @@ pub enum ItemStateError { NoRoom(RoomId), #[error("floor item {0} not found")] NoFloorItem(ClientItemId), - #[error("expected {0} to be a tool")] NotATool(ClientItemId), - #[error("bank item {0} not found")] NoBankItem(ClientItemId), - #[error("inventory error {0}")] InventoryError(#[from] InventoryError), - #[error("bank error {0}")] BankError(#[from] BankError), - #[error("invalid item id {0}")] InvalidItemId(ClientItemId), - #[error("invalid drop? {0:?} (this shouldn't occur)")] BadItemDrop(ItemDrop), - #[error("idk")] Dummy, - #[error("gateway")] GatewayError(#[from] GatewayError), - #[error("tried to remove more meseta than exists: {0}")] InvalidMesetaRemoval(u32), - #[error("tried to add meseta when there is no more room")] FullOfMeseta, - #[error("stacked item")] StackedItemError(Vec), - #[error("apply item {0}")] ApplyItemError(#[from] crate::ship::items::apply_item::ApplyItemError), - #[error("item is not a mag {0}")] NotAMag(ClientItemId), - #[error("item is not mag food {0}")] NotMagFood(ClientItemId), - #[error("item is not sellable")] ItemNotSellable, - #[error("could not modify item")] InvalidModifier, - #[error("wrong item type ")] WrongItemType(ClientItemId), } @@ -137,7 +116,6 @@ impl StackedItemDetail { } - #[derive(Clone)] pub enum AddItemResult { NewItem, @@ -177,7 +155,7 @@ impl ItemState { .read() .await .get(&character.id) - .ok_or(ItemStateError::NoCharacter(character.id))? + .ok_or_else(|| ItemStateError::NoCharacter(character.id))? .read() .await .clone()) @@ -188,7 +166,7 @@ impl ItemState { .read() .await .get(&character.id) - .ok_or(ItemStateError::NoCharacter(character.id))? + .ok_or_else(|| ItemStateError::NoCharacter(character.id))? .read() .await .clone()) @@ -197,7 +175,6 @@ impl ItemState { impl ItemState { async fn new_item_id(&mut self) -> Result { - //self.room_item_id_counter += 1; *self.room_item_id_counter .write() .await += 1; @@ -300,7 +277,6 @@ impl ItemState { pub async fn add_character_to_room(&mut self, room_id: RoomId, character: &CharacterEntity, area_client: AreaClient) { let base_inventory_id = ((area_client.local_client.id() as u32) << 21) | 0x10000; - //let inventory = self.character_inventory.get_mut(&character.id).unwrap(); self.character_inventory .read() .await @@ -309,9 +285,7 @@ impl ItemState { .write() .await .initialize_item_ids(base_inventory_id); - //inventory.initialize_item_ids(base_inventory_id); let base_bank_id = ((area_client.local_client.id() as u32) << 21) | 0x20000; - //let default_bank = self.character_bank.get_mut(&character.id); self.character_bank .read() .await @@ -320,9 +294,6 @@ impl ItemState { .write() .await .initialize_item_ids(base_bank_id); - //if let Some(default_bank) = default_bank { - //default_bank.initialize_item_ids(base_bank_id); - //} self.character_room .write() .await @@ -369,7 +340,7 @@ impl ItemState { .await; let local_floor = local_floors .get(character_id) - .ok_or(ItemStateError::NoCharacter(*character_id))? + .ok_or_else(|| ItemStateError::NoCharacter(*character_id))? .read() .await; let rooms = self.character_room @@ -377,13 +348,13 @@ impl ItemState { .await; let room = rooms .get(character_id) - .ok_or(ItemStateError::NoCharacter(*character_id))?; + .ok_or_else(||ItemStateError::NoCharacter(*character_id))?; let shared_floors = self.room_floor .read() .await; let shared_floor = shared_floors .get(room) - .ok_or(ItemStateError::NoCharacter(*character_id))? + .ok_or_else(||ItemStateError::NoCharacter(*character_id))? .read() .await; @@ -397,7 +368,7 @@ impl ItemState { .find(|item| item.item_id == *item_id) .map(|item| (item.clone(), FloorType::Shared)) }) - .ok_or(ItemStateError::NoFloorItem(*item_id)) + .ok_or_else(|| ItemStateError::NoFloorItem(*item_id)) } } @@ -415,12 +386,10 @@ struct ProxiedItemState { pub struct ItemStateProxy<'a> { item_state: &'a mut ItemState, proxied_state: ProxiedItemState, - //_a: std::marker::PhantomData<&'a ()>, // TODO: remove } impl<'a> ItemStateProxy<'a> { pub async fn commit(self) { - async fn copy_back(master: &Arc>>>, proxy: HashMap) where @@ -443,43 +412,6 @@ impl<'a> ItemStateProxy<'a> { //copy_back(self.item_state.character_room, self.proxied_state.character_room).await; copy_back(&self.item_state.character_floor, self.proxied_state.character_floor).await; copy_back(&self.item_state.room_floor, self.proxied_state.room_floor).await; - - - /* - self.item_state.character_inventory - .write() - .await - .extend(self.proxied_state.character_inventory.clone()); - self.item_state.character_bank - .write() - .await - .extend(self.proxied_state.character_bank.clone()); - self.item_state.character_room - .write() - .await - .extend(self.proxied_state.character_room.clone()); - self.item_state.character_floor - .write() - .await - .extend(self.proxied_state.character_floor.clone()); - self.item_state.room_floor - .write() - .await - .extend(self.proxied_state.room_floor); - */ - /* - for (character_id, character_inventory) in self.proxied_state.character_inventory { - if let Some(inventory) = self.item_state.character_inventory - .read() - .await - .get(&character_id) { - *inventory - .write() - .await = character_inventory; - } - } - */ - } } @@ -492,11 +424,6 @@ where K: Eq + std::hash::Hash + Copy, V: Clone { - /* - let existing_element = master.get(&key).ok_or_else(|| err(key))?; - Ok(proxy.entry(key) - .or_insert_with(|| existing_element.clone()).clone()) - */ let existing_element = master .read() .await @@ -516,7 +443,6 @@ impl<'a> ItemStateProxy<'a> { ItemStateProxy { item_state, proxied_state: Default::default(), - //_a: Default::default(), } } @@ -543,7 +469,6 @@ impl<'a> ItemStateProxy<'a> { } pub async fn floor(&mut self, character_id: &CharacterEntityId) -> Result { - //let room_id = get_or_clone(&self.item_state.character_room, &mut self.proxied_state.character_room, *character_id, ItemStateError::NoCharacter)?; let room_id = *self.item_state.character_room.read().await.get(character_id).unwrap(); Ok(FloorState { character_id: *character_id, @@ -553,7 +478,6 @@ impl<'a> ItemStateProxy<'a> { } pub async fn set_floor(&mut self, floor: FloorState) { - //let room_id = get_or_clone(&self.item_state.character_room, &mut self.proxied_state.character_room, floor.character_id, ItemStateError::NoCharacter).unwrap(); let room_id = *self.item_state.character_room.read().await.get(&floor.character_id).unwrap(); self.proxied_state.character_floor.insert(floor.character_id, floor.local); self.proxied_state.room_floor.insert(room_id, floor.shared); diff --git a/src/ship/map/area.rs b/src/ship/map/area.rs index 4cb22ee..02361c3 100644 --- a/src/ship/map/area.rs +++ b/src/ship/map/area.rs @@ -320,7 +320,7 @@ pub struct MapAreaLookup(HashMap); impl MapAreaLookup { pub fn get_area_map(&self, map_area: u16) -> Result { self.0.get(&map_area) - .map(|a| *a) + .copied() .ok_or(MapAreaError::UnknownMapArea(map_area)) } diff --git a/src/ship/packet/builder/lobby.rs b/src/ship/packet/builder/lobby.rs index 86da981..2571766 100644 --- a/src/ship/packet/builder/lobby.rs +++ b/src/ship/packet/builder/lobby.rs @@ -43,7 +43,7 @@ pub async fn join_lobby(id: ClientId, block: client_block, event: 0, padding: 0, - playerinfo: playerinfo, + playerinfo, }) } diff --git a/src/ship/packet/handler/auth.rs b/src/ship/packet/handler/auth.rs index 1ae4137..ddbfeeb 100644 --- a/src/ship/packet/handler/auth.rs +++ b/src/ship/packet/handler/auth.rs @@ -23,20 +23,21 @@ where Ok(match get_login_status(entity_gateway, &pkt).await { Ok(user) => { let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::new()); - response.guildcard = user.id.0 as u32; - response.team_id = user.team_id.map_or(31, |ti| ti) as u32; + response.guildcard = user.id.0; + response.team_id = user.team_id.map_or(31, |ti| ti); let characters = entity_gateway.get_characters_by_user(&user).await?; let character = characters .get(pkt.session.character_slot as usize) - .ok_or(ShipError::InvalidSlot(id, pkt.session.character_slot as u32))?.as_ref() - .ok_or(ShipError::NoCharacterInSlot(id, pkt.session.character_slot as u32))? + .ok_or_else(|| ShipError::InvalidSlot(id, pkt.session.character_slot as u32))? + .as_ref() + .ok_or_else(|| ShipError::NoCharacterInSlot(id, pkt.session.character_slot as u32))? .clone(); let settings = entity_gateway.get_user_settings_by_user(&user).await?; item_state.load_character(entity_gateway, &character).await?; if let Some(shipgate_sender) = shipgate_sender.as_ref() { - shipgate_sender.send(ShipMessage::AddUser(user.id)).await; + shipgate_sender.send(ShipMessage::AddUser(user.id)).await?; } clients.add(id, ClientState::new(user, settings, character, pkt.session)).await; vec![SendShipPacket::LoginResponse(response), SendShipPacket::ShipBlockList(ShipBlockList::new(ship_name, num_blocks))] diff --git a/src/ship/packet/handler/communication.rs b/src/ship/packet/handler/communication.rs index eb16508..0a80304 100644 --- a/src/ship/packet/handler/communication.rs +++ b/src/ship/packet/handler/communication.rs @@ -17,7 +17,7 @@ pub async fn player_chat(id: ClientId, Ok(client_location.get_all_clients_by_client(id).await.unwrap().into_iter() .map(move |client| { - (client.client, SendShipPacket::PlayerChat(cmsg.clone()).clone()) + (client.client, SendShipPacket::PlayerChat(cmsg.clone())) }) .collect()) } diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index 29c64cf..f565d41 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -6,7 +6,7 @@ use libpso::packet::messages::*; use crate::common::leveltable::LEVEL_TABLE; use crate::common::serverstate::ClientId; use crate::ship::ship::{SendShipPacket, ShipError, Clients, ItemShops}; -use crate::ship::location::{ClientLocation, ClientLocationError}; +use crate::ship::location::ClientLocation; use crate::ship::drops::ItemDrop; use crate::ship::room::Rooms; use crate::ship::items::ClientItemId; @@ -86,16 +86,16 @@ pub async fn request_item(id: ClientId, where EG: EntityGateway { - let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let room_id = client_location.get_room(id).await?; let monster = rooms.with(room_id, |room| Box::pin(async move { room.maps.enemy_by_id(request_item.enemy_id as usize) })).await??; if monster.dropped_item { - return Err(ShipError::MonsterAlreadyDroppedItem(id, request_item.enemy_id).into()) + return Err(ShipError::MonsterAlreadyDroppedItem(id, request_item.enemy_id)) } - let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let clients_in_area = client_location.get_clients_in_room(room_id).await?; let client_and_drop = rooms.with_mut(room_id, |room| Box::pin(async move { clients_in_area.into_iter() .filter_map(move |area_client| { @@ -138,9 +138,9 @@ pub async fn pickup_item(id: ClientId, where EG: EntityGateway + Clone + 'static, { - let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let area_client = client_location.get_local_client(id).await?; + let room_id = client_location.get_room(id).await?; + let clients_in_area = client_location.get_clients_in_room(room_id).await?; clients.with(id, |client| { let mut entity_gateway = entity_gateway.clone(); @@ -197,16 +197,16 @@ pub async fn request_box_item(id: ClientId, where EG: EntityGateway + Clone + 'static { - let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let room_id = client_location.get_room(id).await?; let box_object = rooms.with(room_id, |room| Box::pin(async move { room.maps.object_by_id(box_drop_request.object_id as usize) })).await??; if box_object.dropped_item { - return Err(ShipError::BoxAlreadyDroppedItem(id, box_drop_request.object_id).into()) + return Err(ShipError::BoxAlreadyDroppedItem(id, box_drop_request.object_id)) } - let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let clients_in_area = client_location.get_clients_in_room(room_id).await?; let client_and_drop = rooms.with_mut(room_id, |room| Box::pin(async move { clients_in_area.into_iter() @@ -266,8 +266,8 @@ pub async fn bank_interaction(id: ClientId, where EG: EntityGateway + Clone + 'static, { - let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let other_clients_in_area = client_location.get_all_clients_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let area_client = client_location.get_local_client(id).await?; + let other_clients_in_area = client_location.get_all_clients_by_client(id).await?; let bank_action_pkts = clients.with(id, |client| { let mut entity_gateway = entity_gateway.clone(); @@ -323,7 +323,7 @@ pub async fn shop_request(id: ClientId, -> Result, ShipError> { //let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let room_id = client_location.get_room(id).await?; /* let room = rooms.get(room_id.0) .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? @@ -401,7 +401,7 @@ pub async fn buy_item(id: ClientId, where EG: EntityGateway + Clone + 'static, { - let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let area_client = client_location.get_local_client(id).await?; let create = clients.with_mut(id, |client| { let mut entity_gateway = entity_gateway.clone(); @@ -422,7 +422,7 @@ where (item, remove) }, _ => { - return Err(ShipError::ShopError.into()) + return Err(ShipError::ShopError) } }; @@ -442,7 +442,7 @@ where builder::message::create_withdrawn_inventory_item(area_client, &inventory_item) })}).await??; - let other_clients_in_area = client_location.get_client_neighbors(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let other_clients_in_area = client_location.get_client_neighbors(id).await?; Ok(other_clients_in_area.into_iter() .map(move |c| { (c.client, SendShipPacket::Message(Message::new(GameMessage::CreateItem(create.clone())))) @@ -489,11 +489,11 @@ where let inventory = item_state.get_character_inventory(&client.character).await?; let item = inventory.get_by_client_id(&ClientItemId(tek_request.item_id)) - .ok_or(ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))?; + .ok_or_else(|| ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))?; let mut weapon = *item.item.as_individual() - .ok_or(ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))? + .ok_or_else(|| ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))? .as_weapon() - .ok_or(ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))?; + .ok_or_else(|| ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))?; weapon.apply_modifier(&item::weapon::WeaponModifier::Tekked { special: special_mod, @@ -519,8 +519,8 @@ pub async fn accept_tek_item(id: ClientId, where EG: EntityGateway + Clone + 'static, { - let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - let neighbors = client_location.get_client_neighbors(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let area_client = client_location.get_local_client(id).await?; + let neighbors = client_location.get_client_neighbors(id).await?; clients.with(id, |client| { let mut entity_gateway = entity_gateway.clone(); diff --git a/src/ship/packet/handler/lobby.rs b/src/ship/packet/handler/lobby.rs index 692740e..287ea41 100644 --- a/src/ship/packet/handler/lobby.rs +++ b/src/ship/packet/handler/lobby.rs @@ -146,45 +146,17 @@ pub async fn remove_from_lobby(id: ClientId, pub async fn get_room_tab_info(id: ClientId, pkt: MenuDetail, client_location: &mut ClientLocation, - clients: &Clients, - rooms: &mut Rooms) + clients: &Clients) -> Result, ShipError> { - /* let room_id = RoomId(pkt.item as usize); - if let Some(_room) = rooms.get(pkt.item as usize).ok_or(ShipError::InvalidRoom(pkt.item))? { - let mut room_info = String::new(); - let clients_in_room = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; - for client in clients_in_room { - let cs = clients.get(&client.client).ok_or(ShipError::ClientNotFound(client.client))?; - let gc = cs.user.guildcard; - let name = &cs.character.name; - let cc = cs.character.char_class; - let lv = LEVEL_TABLE.get_level_from_exp(cc, cs.character.exp); - let floor = cs.area.unwrap_or(MapArea::Pioneer2Ep1); - - room_info += format!("{} Lv{} {}\n{} {}\n", gc,lv,name,cc,floor).as_str(); - } - Ok(vec![(id, SendShipPacket::SmallLeftDialog(SmallLeftDialog::new(room_info)))]) - } else { - Ok(vec![(id, SendShipPacket::SmallLeftDialog(SmallLeftDialog::new("Game is no longer active".into())))]) - } - */ - dbg!("a"); - let room_id = RoomId(pkt.item as usize); - dbg!("b"); let clients_in_room = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; - dbg!("c"); - let room_info = if clients_in_room.len() == 0 { - dbg!("d"); + let room_info = if clients_in_room.is_empty() { String::from("Game is no longer active") } else { - dbg!("d2"); join_all(clients_in_room.iter() .map(|clientl| async move { - dbg!("e"); clients.with(clientl.client, |client| Box::pin(async move { - dbg!("f"); format!("{} Lv{} {}\n{} {}", client.character.name, LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp), diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs index 823b83b..df8b7d0 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -28,7 +28,7 @@ where let enemy_id = request_exp.enemy_id as usize; let enemy_exp = rooms.with(room_id, |room| Box::pin(async move { let monster = room.maps.enemy_by_id(enemy_id)?; - let monster_stats = room.monster_stats.get(&monster.monster).ok_or(ShipError::UnknownMonster(monster.monster))?; + let monster_stats = room.monster_stats.get(&monster.monster).ok_or_else(|| ShipError::UnknownMonster(monster.monster))?; Ok::<_, ShipError>(monster_stats.exp) })).await??; @@ -150,7 +150,7 @@ where })).await?; if let Some(drop_location) = drop_location { if drop_location.item_id.0 != no_longer_has_item.item_id { - return Err(ShipError::DropInvalidItemId(no_longer_has_item.item_id).into()); + return Err(ShipError::DropInvalidItemId(no_longer_has_item.item_id)); } if no_longer_has_item.item_id == 0xFFFFFFFF { @@ -163,7 +163,7 @@ where })}).await??; let dropped_meseta_pkt = builder::message::drop_split_meseta_stack(area_client, &dropped_meseta)?; - let no_longer_has_meseta_pkt = builder::message::player_no_longer_has_meseta(area_client, no_longer_has_item.amount as u32); + let no_longer_has_meseta_pkt = builder::message::player_no_longer_has_meseta(area_client, no_longer_has_item.amount); let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; Ok(clients_in_area.into_iter() @@ -218,7 +218,7 @@ where .collect()) } else { - Err(ShipError::InvalidItem(ClientItemId(no_longer_has_item.item_id)).into()) + Err(ShipError::InvalidItem(ClientItemId(no_longer_has_item.item_id))) } } @@ -292,7 +292,7 @@ pub async fn update_player_position(id: ClientId, _ => {}, } Ok::<_, ShipError>(()) - })}).await?; + })}).await??; } Ok(client_location.get_client_neighbors(id).await?.into_iter() .map(move |client| { diff --git a/src/ship/packet/handler/quest.rs b/src/ship/packet/handler/quest.rs index 8df47fd..9df89b9 100644 --- a/src/ship/packet/handler/quest.rs +++ b/src/ship/packet/handler/quest.rs @@ -8,7 +8,6 @@ use crate::ship::location::{ClientLocation, ClientLocationError}; use crate::ship::packet::builder::quest; use libpso::util::array_to_utf8; -// TOOD: enum enum QuestFileType { Bin, Dat @@ -44,16 +43,6 @@ pub async fn send_quest_category_list(id: ClientId, rooms: &Rooms) -> Result, ShipError> { let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - /* - let mut room = rooms.get_mut(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? - .write() - .await; - let qcl = quest::quest_category_list(&room.quests[rql.flag.clamp(0, (room.quests.len() - 1) as u32) as usize]); - room.set_quest_group(rql.flag as usize); - Ok(Box::new(vec![(id, SendShipPacket::QuestCategoryList(qcl))].into_iter())) - */ let rql = rql.clone(); rooms.with_mut(room_id, |room| Box::pin(async move { let qcl = quest::quest_category_list(&room.quests[rql.flag.clamp(0, (room.quests.len() - 1) as u32) as usize]); @@ -71,7 +60,7 @@ pub async fn select_quest_category(id: ClientId, rooms.with(room_id, |room| Box::pin(async move { let (_, category_quests) = room.quests[room.quest_group.value()].iter() .nth(menuselect.item as usize) - .ok_or(ShipError::InvalidQuestCategory(menuselect.item))?; + .ok_or_else(|| ShipError::InvalidQuestCategory(menuselect.item as u16))?; let ql = quest::quest_list(menuselect.item, category_quests); Ok(vec![(id, SendShipPacket::QuestOptionList(ql))]) @@ -88,12 +77,12 @@ pub async fn quest_detail(id: ClientId, rooms.with(room_id, |room| Box::pin(async move { let (_, category_quests) = room.quests[room.quest_group.value()].iter() .nth(questdetailrequest.category as usize) - .ok_or(ShipError::InvalidQuestCategory(questdetailrequest.category as u32))?; + .ok_or_else(|| ShipError::InvalidQuestCategory(questdetailrequest.category))?; let quest = category_quests.iter() .find(|q| { - q.id == questdetailrequest.quest as u16 - }).ok_or(ShipError::InvalidQuest(questdetailrequest.quest as u32))?; + q.id == questdetailrequest.quest + }).ok_or_else(|| ShipError::InvalidQuest(questdetailrequest.quest))?; let qd = quest::quest_detail(quest); @@ -116,13 +105,13 @@ pub async fn player_chose_quest(id: ClientId, Box::pin(async move { let quest = room.quests[room.quest_group.value()].iter() .nth(questmenuselect.category as usize) - .ok_or(ShipError::InvalidQuestCategory(questmenuselect.category as u32))? + .ok_or_else(|| ShipError::InvalidQuestCategory(questmenuselect.category))? .1 .iter() .find(|q| { - q.id == questmenuselect.quest as u16 + q.id == questmenuselect.quest }) - .ok_or(ShipError::InvalidQuest(questmenuselect.quest as u32))? + .ok_or_else(|| ShipError::InvalidQuest(questmenuselect.quest))? .clone(); let rare_monster_drops = room.rare_monster_table.clone(); @@ -138,11 +127,6 @@ pub async fn player_chose_quest(id: ClientId, client.done_loading_quest = false; })).await?; } - //area_clients.iter().for_each(|c| { - //if let Some(client) = clients.get_mut(&c.client) { - // client.done_loading_quest = false; - //} - //}); Ok(area_clients .into_iter() .flat_map(move |c| { @@ -150,53 +134,6 @@ pub async fn player_chose_quest(id: ClientId, }) .collect()) })}).await? - /* - let mut room = rooms.get(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? - .as_ref() - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? - .write() - .await; - /* - let (_, category_quests) = room.quests[room.quest_group.value()].iter() - .nth(questmenuselect.category as usize) - .ok_or(ShipError::InvalidQuestCategory(questmenuselect.category as u32))?; - - let quest = category_quests.iter() - .find(|q| { - q.id == questmenuselect.quest as u16 -}).ok_or(ShipError::InvalidQuest(questmenuselect.quest as u32))? - .clone(); - */ - - let quest = room.quests[room.quest_group.value()].iter() - .nth(questmenuselect.category as usize) - .ok_or(ShipError::InvalidQuestCategory(questmenuselect.category as u32))? - .1 - .iter() - .find(|q| { - q.id == questmenuselect.quest as u16 -}) - .ok_or(ShipError::InvalidQuest(questmenuselect.quest as u32))? - .clone(); - - let rare_monster_drops = room.rare_monster_table.clone(); - room.maps.set_quest_data(quest.enemies.clone(), quest.objects.clone(), &rare_monster_drops); - room.map_areas = quest.map_areas.clone(); - - let bin = quest::quest_header(questmenuselect, &quest.bin_blob, "bin"); - let dat = quest::quest_header(questmenuselect, &quest.dat_blob, "dat"); - - let area_clients = client_location.get_all_clients_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; - area_clients.iter().for_each(|c| { - if let Some(client) = clients.get_mut(&c.client) { - client.done_loading_quest = false; -} -}); - Ok(Box::new(area_clients.into_iter().flat_map(move |c| { - vec![(c.client, SendShipPacket::QuestHeader(bin.clone())), (c.client, SendShipPacket::QuestHeader(dat.clone()))] -}))) - */ } pub async fn quest_file_request(id: ClientId, @@ -212,12 +149,12 @@ pub async fn quest_file_request(id: ClientId, let (category_id, quest_id, datatype) = parse_filename(&quest_file_request.filename)?; let (_, category_quests) = room.quests[room.quest_group.value()].iter() .nth(category_id as usize) - .ok_or(ShipError::InvalidQuestCategory(category_id as u32))?; + .ok_or_else(|| ShipError::InvalidQuestCategory(category_id))?; let quest = category_quests.iter() .find(|q| { - q.id == quest_id as u16 - }).ok_or(ShipError::InvalidQuest(quest_id as u32))?; + q.id == quest_id + }).ok_or_else(|| ShipError::InvalidQuest(quest_id))?; let blob = match datatype { QuestFileType::Bin => &quest.bin_blob, @@ -245,12 +182,12 @@ pub async fn quest_chunk_ack(id: ClientId, let (category_id, quest_id, datatype) = parse_filename(&quest_chunk_ack.filename)?; let (_, category_quests) = room.quests[room.quest_group.value()].iter() .nth(category_id as usize) - .ok_or(ShipError::InvalidQuestCategory(category_id as u32))?; + .ok_or_else(|| ShipError::InvalidQuestCategory(category_id))?; let quest = category_quests.iter() .find(|q| { q.id == quest_id - }).ok_or(ShipError::InvalidQuest(quest_id as u32))?; + }).ok_or_else(|| ShipError::InvalidQuest(quest_id))?; let blob = match datatype { QuestFileType::Bin => &quest.bin_blob, @@ -268,41 +205,6 @@ pub async fn quest_chunk_ack(id: ClientId, Ok(vec![(id, SendShipPacket::QuestChunk(qc))]) })).await? - - /* - let mut room = rooms.get(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? - .write() - .await - .as_ref() - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; - - let (category_id, quest_id, datatype) = parse_filename(&quest_chunk_ack.filename)?; - let (_, category_quests) = room.quests[room.quest_group.value()].iter() - .nth(category_id as usize) - .ok_or(ShipError::InvalidQuestCategory(category_id as u32))?; - - let quest = category_quests.iter() - .find(|q| { - q.id == quest_id -}).ok_or(ShipError::InvalidQuest(quest_id as u32))?; - - let blob = match datatype { - QuestFileType::Bin => &quest.bin_blob, - QuestFileType::Dat => &quest.dat_blob, -}; - - let mut blob_cursor = Cursor::new(&**blob); - blob_cursor.seek(SeekFrom::Start((quest_chunk_ack.chunk_num as u64 + 1) * 0x400))?; - let mut subblob = [0u8; 0x400]; - let blob_length = blob_cursor.read(&mut subblob)?; - if blob_length == 0 { - return Ok(Box::new(None.into_iter())); -} - let qc = quest::quest_chunk(quest_chunk_ack.chunk_num + 1, quest_chunk_ack.filename, subblob, blob_length); - - Ok(Box::new(vec![(id, SendShipPacket::QuestChunk(qc))].into_iter())) - */ } pub async fn done_loading_quest(id: ClientId, @@ -315,14 +217,14 @@ pub async fn done_loading_quest(id: ClientId, let area_clients = client_location.get_all_clients_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let all_loaded = area_clients.iter() - .map(|client| async { - clients.with(client.client, |client| Box::pin(async move { - client.done_loading_quest - })) - }) + .map(|client| + clients.with(client.client, |client| Box::pin(async move { + client.done_loading_quest + })) + ) .collect::>() .all(|c| async move { - c.await.unwrap_or(false) + c.unwrap_or(false) }).await; if all_loaded { diff --git a/src/ship/packet/handler/room.rs b/src/ship/packet/handler/room.rs index ab3e79a..7653abc 100644 --- a/src/ship/packet/handler/room.rs +++ b/src/ship/packet/handler/room.rs @@ -1,16 +1,16 @@ +use std::convert::{TryFrom, Into}; +use futures::stream::StreamExt; + use libpso::packet::ship::*; use libpso::packet::messages::*; use crate::common::serverstate::ClientId; use crate::common::leveltable::LEVEL_TABLE; use crate::ship::ship::{SendShipPacket, ShipError, Clients}; use crate::ship::room::Rooms; -use crate::ship::location::{ClientLocation, RoomId, RoomLobby, ClientLocationError, GetAreaError}; +use crate::ship::location::{ClientLocation, RoomId, RoomLobby, GetAreaError}; use crate::ship::packet::builder; use crate::ship::room; use crate::ship::items::state::ItemState; -use std::convert::{TryFrom, Into}; -use async_std::sync::{Arc, RwLock}; -use futures::stream::{FuturesOrdered, StreamExt}; pub async fn create_room(id: ClientId, create_room: CreateRoom, @@ -39,7 +39,6 @@ pub async fn create_room(id: ClientId, let area_client = client_location.get_local_client(id).await?; let lobby_neighbors = client_location.get_client_neighbors(id).await?; - //let room_id = client_location.create_new_room(id).await.map_err(Into::::into)?; let room_id = client_location.create_new_room(id).await?; let room = clients.with(id, |client| { let mut item_state = item_state.clone(); @@ -66,7 +65,6 @@ pub async fn create_room(id: ClientId, Ok(result) } -// TODO: remove unwraps pub async fn room_name_request(id: ClientId, client_location: &ClientLocation, rooms: &Rooms) @@ -81,7 +79,6 @@ pub async fn room_name_request(id: ClientId, })).await }, RoomLobby::Lobby(_) => Err(GetAreaError::NotInRoom.into()) - //RoomLobby::Lobby(_) => Err(ShipError::ClientLocationError(GetAreaError::NotInRoom)) } } @@ -125,8 +122,7 @@ pub async fn join_room(id: ClientId, let original_room_clients = client_location.get_clients_in_room(room_id).await?; client_location.add_client_to_room(id, room_id).await?; let area_client = client_location.get_local_client(id).await?; - //let original_leader = client_location.get_area_leader(original_area).await.unwrap(); - let room_leader = client_location.get_room_leader(room_id).await.unwrap(); + let room_leader = client_location.get_room_leader(room_id).await?; clients.with(id, |client| { let mut item_state = item_state.clone(); @@ -138,14 +134,13 @@ pub async fn join_room(id: ClientId, let clients = clients.clone(); let client_location = client_location.clone(); Box::pin(async move { - builder::room::join_room(id, &clients, &client_location, room_id, &room).await + builder::room::join_room(id, &clients, &client_location, room_id, room).await })}).await??; let add_to = clients.with(id, |client| { let item_state = item_state.clone(); Box::pin(async move { builder::room::add_to_room(id, client, &area_client, &room_leader, &item_state, room_id).await })}).await??; - //let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), original_leader.local_client.id())); rooms.with_mut(room_id, |room| Box::pin(async move { room.bursting = true; @@ -161,7 +156,7 @@ pub async fn join_room(id: ClientId, async move { client_location.get_area_leader(original_area).await.ok().map(|leader| { let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())); - (c.client, leave_lobby.clone()) + (c.client, leave_lobby) }) } }) @@ -169,37 +164,6 @@ pub async fn join_room(id: ClientId, .await ) .collect()) - - /* - if let Ok(leader) = client_location.get_area_leader(original_area).await { - let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())); - result.extend(original_neighbors.into_iter() - .map(move |c| (c.client, leave_lobby.clone()))) - } - */ - - //Ok(result) - /* - - if let Some(room) = &mut *rooms.get(pkt.item as usize).ok_or(ShipError::InvalidRoom(pkt.item))?.write().await { - let mut result: Box + Send> = Box::new( - vec![(id, SendShipPacket::JoinRoom(join_room))] - .into_iter() - .chain(original_room_clients.into_iter() - .map(move |c| (c.client, SendShipPacket::AddToRoom(add_to.clone()))) - )); - - if let Ok(leader) = client_location.get_area_leader(original_area).await { - let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())); - result = Box::new(result.chain(original_neighbors.into_iter() - .map(move |c| (c.client, leave_lobby.clone())))) - } - - Ok(result.collect()) - } else { - Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Game is no longer active".into())))]) - } - */ } pub async fn done_bursting(id: ClientId, @@ -230,7 +194,6 @@ pub async fn request_room_list(id: ClientId, client_location: &ClientLocation, rooms: &Rooms) -> Vec<(ClientId, SendShipPacket)> { - //let active_room_list = futures::stream::iter(rooms.iter()) let active_room_list = rooms.stream() .enumerate() .filter_map(|(i, r)| async move { @@ -270,17 +233,16 @@ pub async fn request_room_list(id: ClientId, pub async fn cool_62(id: ClientId, cool_62: Like62ButCooler, client_location: &ClientLocation) - -> Vec<(ClientId, SendShipPacket)> { + -> Result, ShipError> { let target = cool_62.flag as u8; let cool_62 = cool_62.clone(); - client_location + Ok(client_location .get_client_neighbors(id) - .await - .unwrap() + .await? .into_iter() .filter(move |client| client.local_client.id() == target) .map(move |client| { (client.client, SendShipPacket::Like62ButCooler(cool_62.clone())) }) - .collect() + .collect()) } diff --git a/src/ship/packet/handler/ship.rs b/src/ship/packet/handler/ship.rs index b9505f3..b393e61 100644 --- a/src/ship/packet/handler/ship.rs +++ b/src/ship/packet/handler/ship.rs @@ -15,7 +15,7 @@ pub fn block_list(id: ClientId, shipname: &str, num_blocks: usize) -> Vec<(Clien pub fn selected_ship(id: ClientId, menuselect: MenuSelect, ship_list: &[Ship]) -> Result, ShipError> { - let ship = ship_list.get(menuselect.item as usize).ok_or(ShipError::InvalidShip(menuselect.item as usize))?; + let ship = ship_list.get(menuselect.item as usize).ok_or_else(|| ShipError::InvalidShip(menuselect.item as usize))?; let ip = u32::from_ne_bytes(ship.ip.octets()); Ok(vec![(id, SendShipPacket::RedirectClient(RedirectClient::new(ip, ship.port)))]) } diff --git a/src/ship/packet/handler/trade.rs b/src/ship/packet/handler/trade.rs index b7b6cd5..f369f96 100644 --- a/src/ship/packet/handler/trade.rs +++ b/src/ship/packet/handler/trade.rs @@ -154,7 +154,7 @@ pub async fn trade_request(id: ClientId, this.meseta += amount as usize; } else { - let item = inventory.get_by_client_id(&ClientItemId(item_id)).ok_or(ItemStateError::InvalidItemId(ClientItemId(item_id)))?; + let item = inventory.get_by_client_id(&ClientItemId(item_id)).ok_or_else(|| ItemStateError::InvalidItemId(ClientItemId(item_id)))?; match &item.item { InventoryItemDetail::Individual(_) => { @@ -192,7 +192,7 @@ pub async fn trade_request(id: ClientId, this.meseta -= amount as usize; } else { - let item = inventory.get_by_client_id(&ClientItemId(item_id)).ok_or(ItemStateError::InvalidItemId(ClientItemId(item_id)))?; + let item = inventory.get_by_client_id(&ClientItemId(item_id)).ok_or_else(|| ItemStateError::InvalidItemId(ClientItemId(item_id)))?; match &item.item { InventoryItemDetail::Individual(_) => { @@ -207,9 +207,9 @@ pub async fn trade_request(id: ClientId, }) .ok_or(TradeError::InvalidItemId(ClientItemId(item_id)))?; - match this.items[trade_item_index].stacked().ok_or(ItemStateError::InvalidItemId(ClientItemId(item_id)))?.1.cmp(&(amount as usize)) { + match this.items[trade_item_index].stacked().ok_or_else(|| ItemStateError::InvalidItemId(ClientItemId(item_id)))?.1.cmp(&(amount as usize)) { std::cmp::Ordering::Greater => { - *this.items[trade_item_index].stacked_mut().ok_or(ItemStateError::InvalidItemId(ClientItemId(item_id)))?.1 -= amount as usize; + *this.items[trade_item_index].stacked_mut().ok_or_else(|| ItemStateError::InvalidItemId(ClientItemId(item_id)))?.1 -= amount as usize; }, std::cmp::Ordering::Equal => { this.items.remove(trade_item_index); @@ -314,7 +314,7 @@ async fn inner_items_to_trade(id: ClientId, Ok::<_, ShipError>((this, other_inventory)) })}).await??; - if items_to_trade.count as usize != (this.items.len() + (if this.meseta != 0 { 1 } else { 0 })) { + if items_to_trade.count as usize != (this.items.len() + usize::from(this.meseta != 0)) { return Err(TradeError::MismatchedTradeItems.into()) } @@ -342,7 +342,7 @@ async fn inner_items_to_trade(id: ClientId, } else { let real_item = this_inventory.get_by_client_id(&ClientItemId(item.item_id)) - .ok_or(ItemStateError::InvalidItemId(ClientItemId(item.item_id)))?; + .ok_or_else(|| ItemStateError::InvalidItemId(ClientItemId(item.item_id)))?; let real_trade_item = this.items .iter() .find(|i| i.item_id() == ClientItemId(item.item_id)) diff --git a/src/ship/room.rs b/src/ship/room.rs index 44b4e42..9758064 100644 --- a/src/ship/room.rs +++ b/src/ship/room.rs @@ -1,16 +1,13 @@ use std::collections::HashMap; use std::convert::{From, Into, TryFrom, TryInto}; use std::path::PathBuf; - -use async_std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; -use std::future::Future; -use futures::stream::{Stream, StreamExt, FuturesOrdered}; +use async_std::sync::{Arc, RwLock, RwLockReadGuard}; use futures::future::BoxFuture; +use futures::stream::{FuturesOrdered, Stream}; use thiserror::Error; -use std::ops::Deref; - use rand::Rng; + use crate::ship::map::Maps; use crate::ship::drops::DropTable; use crate::entity::character::SectionID; @@ -19,8 +16,7 @@ use crate::ship::map::area::MapAreaLookup; use crate::ship::map::enemy::RareMonsterAppearTable; use crate::ship::quests; use crate::ship::ship::ShipError; - -use crate::ship::location::{ClientLocation, RoomLobby, MAX_ROOMS, ClientLocationError, GetNeighborError, GetClientsError, GetAreaError, RoomId}; +use crate::ship::location::{MAX_ROOMS, RoomId}; #[derive(Clone)] @@ -32,28 +28,11 @@ impl Default for Rooms { } } - -/* -#[derive(escher::Rebindable)] -struct BorrowedRoom<'a> { - lock: RwLockReadGuard<'a, Option>, - room: &'a Option, -} - -impl<'a> std::ops::Deref for BorrowedRoom<'a> { - type Target = RoomState; - fn deref(&self) -> &Self::Target { - &self.room - } -} -*/ - - impl Rooms { pub async fn add(&self, room_id: RoomId, room: RoomState) -> Result<(), ShipError> { *self.0 .get(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? + .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))? .write() .await = Some(room); Ok(()) @@ -86,7 +65,7 @@ impl Rooms { { let room = self.0 .get(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? + .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))? .read() .await; if let Some(room) = room.as_ref() { @@ -104,7 +83,7 @@ impl Rooms { { let mut room = self.0 .get(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? + .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))? .write() .await; @@ -116,7 +95,7 @@ impl Rooms { } } - pub async fn get<'a>(&'a self, room_id: RoomId) -> RwLockReadGuard<'a, Option> { + pub async fn get(&self, room_id: RoomId) -> RwLockReadGuard> { self.0 .get(room_id.0) .unwrap() @@ -124,7 +103,7 @@ impl Rooms { .await } - pub fn stream<'a>(&'a self) -> impl Stream>> + 'a { + pub fn stream(&self) -> impl Stream>> { self.0 .iter() .map(|room| async move { @@ -136,11 +115,6 @@ impl Rooms { } } - - - - - #[derive(Debug, Error)] #[error("")] pub enum RoomCreationError { diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 77f762d..4dcd8c7 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -9,7 +9,7 @@ use rand::Rng; use thiserror::Error; use libpso::packet::ship::*; -use libpso::packet::login::{RedirectClient, Login, LoginResponse, Session, ShipList}; +use libpso::packet::login::{RedirectClient, Login, LoginResponse, ShipList}; use libpso::packet::messages::*; use libpso::{PacketParseError, PSOPacket}; use libpso::crypto::bb::PSOBBCipher; @@ -24,17 +24,15 @@ use crate::common::interserver::{AuthToken, Ship, ServerId, InterserverActor, Lo use crate::login::character::SHIP_MENU_ID; use crate::entity::gateway::{EntityGateway, GatewayError}; -use crate::entity::account::{UserAccountEntity, UserSettingsEntity}; -use crate::entity::character::{CharacterEntity, SectionID}; -use crate::entity::item; +use crate::entity::character::SectionID; -use crate::ship::location::{ClientLocation, RoomLobby, MAX_ROOMS, ClientLocationError, GetNeighborError, GetClientsError, GetAreaError, RoomId}; +use crate::ship::location::{ClientLocation, RoomLobby, ClientLocationError, RoomId}; use crate::ship::items; use crate::ship::room; -use crate::ship::map::{MapsError, MapAreaError, MapArea}; +use crate::ship::map::{MapsError, MapAreaError}; use crate::ship::packet::handler; -use crate::ship::shops::{WeaponShop, ToolShop, ArmorShop, WeaponShopItem, ToolShopItem, ArmorShopItem}; +use crate::ship::shops::{WeaponShop, ToolShop, ArmorShop}; use crate::ship::trade::TradeState; // TODO: remove once stuff settles down @@ -56,16 +54,7 @@ pub enum ShipError { #[error("too many clients")] TooManyClients, #[error("client error location {0}")] - //ClientLocationError(#[from] ClientLocationError), ClientLocationError(ClientLocationError), - /* - #[error("get neighbor error {0}")] - GetNeighborError(#[from] GetNeighborError), - #[error("get clients error {0}")] - GetClientsError(#[from] GetClientsError), - #[error("get area error {0}")] - GetAreaError(#[from] GetAreaError), - */ #[error("maps error {0}")] MapsError(#[from] MapsError), #[error("map area error {0}")] @@ -89,9 +78,9 @@ pub enum ShipError { #[error("box already dropped item {0} {1}")] BoxAlreadyDroppedItem(ClientId, u16), #[error("invalid quest category {0}")] - InvalidQuestCategory(u32), + InvalidQuestCategory(u16), #[error("invalid quest {0}")] - InvalidQuest(u32), + InvalidQuest(u16), #[error("invalid quest filename {0}")] InvalidQuestFilename(String), #[error("io error {0}")] @@ -118,24 +107,10 @@ pub enum ShipError { MessageError(#[from] crate::ship::packet::handler::direct_message::MessageError), #[error("room creation error {0}")] RoomCreationError(#[from] room::RoomCreationError), + #[error("channel send error {0}")] + SendError(#[from] async_std::channel::SendError), } -/* -impl From for ShipError { - fn from(other: &ClientLocationError) -> ShipError { - - } -} - */ - -/* -impl> Into for I { - fn into(other: I) -> ShipError { - ShipError::ClientLocationError(other.into()) - } -} - */ - impl> From for ShipError { fn from(other: I) -> ShipError { ShipError::ClientLocationError(other.into()) @@ -420,45 +395,23 @@ impl ShipServerStateBuilder { } -#[derive(Clone)] +#[derive(Clone, Default)] pub struct Block { client_location: ClientLocation, pub rooms: room::Rooms, } -impl Default for Block { - fn default() -> Block { - Block { - client_location: ClientLocation::default(), - rooms: room::Rooms::default(), - //rooms: core::array::from_fn(|_| Arc::new(RwLock::new(None))), - } - } -} - -/* -impl Block { - fn with(&self, func: F) -> T - where - T: Send, - F: FnOnce(&Block) -> T, - { - func(self) - } -} -*/ - #[derive(Clone)] pub struct Blocks(pub Vec); impl Blocks { - async fn from_client(&mut self, id: ClientId, clients: &Clients) -> Result<&mut Block, ShipError> { + async fn get_from_client(&mut self, id: ClientId, clients: &Clients) -> Result<&mut Block, ShipError> { let block = clients.with(id, |client| Box::pin(async move { client.block })).await?; self.0 .get_mut(block) - .ok_or(ShipError::InvalidBlock(block)) + .ok_or_else(|| ShipError::InvalidBlock(block)) } } @@ -477,7 +430,6 @@ pub struct ShipServerState { auth_token: AuthToken, ship_list: Vec, - //shipgate_sender: Option>, shipgate_sender: Option>, trades: TradeState, } @@ -490,42 +442,42 @@ impl ShipServerState { async fn message(&mut self, id: ClientId, msg: Message) -> Result, anyhow::Error> { Ok(match msg.msg { GameMessage::RequestExp(request_exp) => { - let block = self.blocks.from_client(id, &self.clients).await?; + let block = self.blocks.get_from_client(id, &self.clients).await?; handler::message::request_exp(id, request_exp, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms).await? }, GameMessage::PlayerDropItem(player_drop_item) => { - let block = self.blocks.from_client(id, &self.clients).await?; + let block = self.blocks.get_from_client(id, &self.clients).await?; handler::message::player_drop_item(id, player_drop_item, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? }, GameMessage::DropCoordinates(drop_coordinates) => { - let block = self.blocks.from_client(id, &self.clients).await?; - handler::message::drop_coordinates(id, drop_coordinates, &block.client_location, &mut self.clients, &block.rooms).await? + let block = self.blocks.get_from_client(id, &self.clients).await?; + handler::message::drop_coordinates(id, drop_coordinates, &block.client_location, &self.clients, &block.rooms).await? }, GameMessage::PlayerNoLongerHasItem(no_longer_has_item) => { - let block = self.blocks.from_client(id, &self.clients).await?; - handler::message::no_longer_has_item(id, no_longer_has_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? + let block = self.blocks.get_from_client(id, &self.clients).await?; + handler::message::no_longer_has_item(id, no_longer_has_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerChangedMap(_) | GameMessage::PlayerChangedMap2(_) | GameMessage::TellOtherPlayerMyLocation(_) | GameMessage::PlayerWarpingToFloor(_) | GameMessage::PlayerTeleported(_) | GameMessage::PlayerStopped(_) | GameMessage::PlayerLoadedIn(_) | GameMessage::PlayerWalking(_) | GameMessage::PlayerRunning(_) | GameMessage::PlayerWarped(_) | GameMessage::PlayerChangedFloor(_) | GameMessage::InitializeSpeechNpc(_) => { - let block = self.blocks.from_client(id, &self.clients).await?; - handler::message::update_player_position(id, msg, &mut self.clients, &block.client_location, &block.rooms).await? + let block = self.blocks.get_from_client(id, &self.clients).await?; + handler::message::update_player_position(id, msg, &self.clients, &block.client_location, &block.rooms).await? }, GameMessage::ChargeAttack(charge_attack) => { - let block = self.blocks.from_client(id, &self.clients).await?; - handler::message::charge_attack(id, charge_attack, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? + let block = self.blocks.get_from_client(id, &self.clients).await?; + handler::message::charge_attack(id, charge_attack, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerUseItem(player_use_item) => { - let block = self.blocks.from_client(id, &self.clients).await?; - handler::message::player_uses_item(id, player_use_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? + let block = self.blocks.get_from_client(id, &self.clients).await?; + handler::message::player_uses_item(id, player_use_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerUsedMedicalCenter(player_used_medical_center) => { - let block = self.blocks.from_client(id, &self.clients).await?; - handler::message::player_used_medical_center(id, player_used_medical_center, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? + let block = self.blocks.get_from_client(id, &self.clients).await?; + handler::message::player_used_medical_center(id, player_used_medical_center, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerFeedMag(player_feed_mag) => { - let block = self.blocks.from_client(id, &self.clients).await?; + let block = self.blocks.get_from_client(id, &self.clients).await?; handler::message::player_feed_mag(id, player_feed_mag, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerEquipItem(player_equip_item) => { @@ -538,11 +490,11 @@ impl ShipServerState { handler::message::player_sorts_items(id, sort_items, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerSoldItem(player_sold_item) => { - handler::message::player_sells_item(id, player_sold_item, &mut self.entity_gateway, &mut self.clients, &mut self.item_state).await? + handler::message::player_sells_item(id, player_sold_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? }, _ => { let cmsg = msg.clone(); - let block = self.blocks.from_client(id, &self.clients).await?; + let block = self.blocks.get_from_client(id, &self.clients).await?; block.client_location.get_client_neighbors(id).await.unwrap().into_iter() .map(move |client| { (client.client, SendShipPacket::Message(cmsg.clone())) @@ -554,7 +506,7 @@ impl ShipServerState { async fn direct_message(&mut self, id: ClientId, msg: DirectMessage) -> Result, anyhow::Error> { let target = msg.flag; - let block = self.blocks.from_client(id, &self.clients).await?; + let block = self.blocks.get_from_client(id, &self.clients).await?; Ok(match msg.msg { GameMessage::GuildcardSend(guildcard_send) => { handler::direct_message::guildcard_send(id, guildcard_send, target, &block.client_location, &self.clients).await? @@ -575,7 +527,7 @@ impl ShipServerState { handler::direct_message::bank_interaction(id, bank_interaction, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? }, GameMessage::ShopRequest(shop_request) => { - handler::direct_message::shop_request(id, shop_request, &block.client_location, &self.clients, &block.rooms, &mut self.shops).await? + handler::direct_message::shop_request(id, shop_request, &block.client_location, &self.clients, &block.rooms, &self.shops).await? }, GameMessage::BuyItem(buy_item) => { handler::direct_message::buy_item(id, buy_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? @@ -630,11 +582,6 @@ impl ServerState for ShipServerState { })).await { self.entity_gateway.set_character_playtime(&char_id, char_playtime).await?; } - /* - if let Some(client) = self.clients.get_mut(&id) { - client.update_playtime(); - self.entity_gateway.set_character_playtime(&client.character.id, client.character.playtime).await?; - }*/ Ok(match pkt { RecvShipPacket::Login(login) => { @@ -645,14 +592,14 @@ impl ServerState for ShipServerState { .collect() }, RecvShipPacket::QuestDetailRequest(questdetailrequest) => { - let block = self.blocks.from_client(id, &self.clients).await?; + let block = self.blocks.get_from_client(id, &self.clients).await?; match questdetailrequest.menu { - QUEST_SELECT_MENU_ID => handler::quest::quest_detail(id, questdetailrequest, &block.client_location, &mut block.rooms).await?, + QUEST_SELECT_MENU_ID => handler::quest::quest_detail(id, questdetailrequest, &block.client_location, &block.rooms).await?, _ => unreachable!(), } }, RecvShipPacket::MenuSelect(menuselect) => { - let block = self.blocks.from_client(id, &self.clients).await?; + let block = self.blocks.get_from_client(id, &self.clients).await?; match menuselect.menu { SHIP_MENU_ID => { let leave_lobby = handler::lobby::remove_from_lobby(id, &mut block.client_location).await.into_iter().into_iter().flatten(); @@ -664,73 +611,39 @@ impl ServerState for ShipServerState { let select_block = handler::lobby::block_selected(id, menuselect, &self.clients, &self.item_state).await?.into_iter(); leave_lobby.chain(select_block).collect() } - ROOM_MENU_ID => handler::room::join_room(id, menuselect, &mut block.client_location, &self.clients, &mut self.item_state, &mut block.rooms).await?, - QUEST_CATEGORY_MENU_ID => handler::quest::select_quest_category(id, menuselect, &block.client_location, &mut block.rooms).await?, + ROOM_MENU_ID => handler::room::join_room(id, menuselect, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms).await?, + QUEST_CATEGORY_MENU_ID => handler::quest::select_quest_category(id, menuselect, &block.client_location, &block.rooms).await?, _ => unreachable!(), } }, RecvShipPacket::QuestMenuSelect(questmenuselect) => { - let block = self.blocks.from_client(id, &self.clients).await?; - handler::quest::player_chose_quest(id, questmenuselect, &mut self.clients, &block.client_location, &mut block.rooms).await? + let block = self.blocks.get_from_client(id, &self.clients).await?; + handler::quest::player_chose_quest(id, questmenuselect, &self.clients, &block.client_location, &block.rooms).await? }, RecvShipPacket::MenuDetail(menudetail) => { - let block = self.blocks.from_client(id, &self.clients).await?; - handler::lobby::get_room_tab_info(id, menudetail, &mut block.client_location, &self.clients, &mut block.rooms).await? + let block = self.blocks.get_from_client(id, &self.clients).await?; + handler::lobby::get_room_tab_info(id, menudetail, &mut block.client_location, &self.clients).await? }, RecvShipPacket::RoomPasswordReq(room_password_req) => { - let block = self.blocks.from_client(id, &self.clients).await?; - - /* - let password = room_password_req.password; - let correct_password = block.rooms.with(RoomId(room_password_req.item as usize), |room| Box::pin(async move { - password == room.password - })).await?; - */ + let block = self.blocks.get_from_client(id, &self.clients).await?; let room_password = block.rooms.with(RoomId(room_password_req.item as usize), |room| Box::pin(async move { room.password })).await?; - /* - let correct_password = room_password_req.password == block.rooms - .get(RoomId(room_password_req.item as usize)) - .await - .map(|room| room.password) - .unwrap_or_else(false); - */ - - //if correct_password { if room_password_req.password == room_password { let menuselect = MenuSelect { menu: room_password_req.menu, item: room_password_req.item, }; - handler::room::join_room(id, menuselect, &mut block.client_location, &mut self.clients, &mut self.item_state, &mut block.rooms).await? + handler::room::join_room(id, menuselect, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms).await? } else { vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Incorrect password".into())))] } - - /* - if room_password_req.password == block.rooms[room_password_req.item as usize] - .read() - .await - .as_ref() - .ok_or(ShipError::InvalidRoom(room_password_req.item))? - .password { - let menuselect = MenuSelect { - menu: room_password_req.menu, - item: room_password_req.item, - }; - handler::room::join_room(id, &menuselect, &mut block.client_location, &mut self.clients, &mut self.item_state, &mut block.rooms).await? - } - else { - Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Incorrect password".into())))].into_iter()) - } - */ }, RecvShipPacket::CharData(chardata) => { - let block = self.blocks.from_client(id, &self.clients).await?; + let block = self.blocks.get_from_client(id, &self.clients).await?; handler::lobby::send_player_to_lobby(id, chardata, &mut block.client_location, &self.clients, &self.item_state).await? }, RecvShipPacket::Message(msg) => { @@ -740,65 +653,65 @@ impl ServerState for ShipServerState { self.direct_message(id, msg).await? }, RecvShipPacket::PlayerChat(msg) => { - let block = self.blocks.from_client(id, &self.clients).await?; + let block = self.blocks.get_from_client(id, &self.clients).await?; handler::communication::player_chat(id, msg, &block.client_location, &self.clients).await? }, RecvShipPacket::CreateRoom(create_room) => { - let block = self.blocks.from_client(id, &self.clients).await?; - handler::room::create_room(id, create_room, &mut block.client_location, &mut self.clients, &mut self.item_state, &mut block.rooms).await? + let block = self.blocks.get_from_client(id, &self.clients).await?; + handler::room::create_room(id, create_room, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms).await? }, RecvShipPacket::RoomNameRequest(_req) => { - let block = self.blocks.from_client(id, &self.clients).await?; + let block = self.blocks.get_from_client(id, &self.clients).await?; handler::room::room_name_request(id, &block.client_location, &block.rooms).await? }, RecvShipPacket::UpdateConfig(pkt) => { - handler::settings::update_config(id, pkt, &mut self.clients, &mut self.entity_gateway).await? + handler::settings::update_config(id, pkt, &self.clients, &mut self.entity_gateway).await? }, RecvShipPacket::ViewInfoboardRequest(_pkt) => { - let block = self.blocks.from_client(id, &self.clients).await?; + let block = self.blocks.get_from_client(id, &self.clients).await?; handler::communication::request_infoboard(id, &block.client_location, &self.clients).await? }, RecvShipPacket::WriteInfoboard(pkt) => { handler::communication::write_infoboard(id, pkt, &self.clients, &mut self.entity_gateway).await? }, RecvShipPacket::RoomListRequest(_req) => { - let block = self.blocks.from_client(id, &self.clients).await?; + let block = self.blocks.get_from_client(id, &self.clients).await?; handler::room::request_room_list(id, &block.client_location, &block.rooms).await }, RecvShipPacket::Like62ButCooler(cool62) => { - let block = self.blocks.from_client(id, &self.clients).await?; - handler::room::cool_62(id, cool62, &block.client_location).await + let block = self.blocks.get_from_client(id, &self.clients).await?; + handler::room::cool_62(id, cool62, &block.client_location).await? }, RecvShipPacket::ClientCharacterData(_) => { // TOOD: validate this in some way? Vec::new() }, RecvShipPacket::DoneBursting(_) => { - let block = self.blocks.from_client(id, &self.clients).await?; - handler::room::done_bursting(id, &block.client_location, &mut block.rooms).await? + let block = self.blocks.get_from_client(id, &self.clients).await?; + handler::room::done_bursting(id, &block.client_location, &block.rooms).await? }, RecvShipPacket::DoneBursting2(_) => { - let block = self.blocks.from_client(id, &self.clients).await?; - handler::room::done_bursting(id, &block.client_location, &mut block.rooms).await? + let block = self.blocks.get_from_client(id, &self.clients).await?; + handler::room::done_bursting(id, &block.client_location, &block.rooms).await? }, RecvShipPacket::LobbySelect(pkt) => { - let block = self.blocks.from_client(id, &self.clients).await?; - handler::lobby::change_lobby(id, pkt.lobby, &mut block.client_location, &self.clients, &mut self.item_state, &mut block.rooms, &mut self.entity_gateway).await? + let block = self.blocks.get_from_client(id, &self.clients).await?; + handler::lobby::change_lobby(id, pkt.lobby, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, &mut self.entity_gateway).await? }, RecvShipPacket::RequestQuestList(rql) => { - let block = self.blocks.from_client(id, &self.clients).await?; - handler::quest::send_quest_category_list(id, rql, &block.client_location, &mut block.rooms).await? + let block = self.blocks.get_from_client(id, &self.clients).await?; + handler::quest::send_quest_category_list(id, rql, &block.client_location, &block.rooms).await? }, RecvShipPacket::QuestFileRequest(quest_file_request) => { - let block = self.blocks.from_client(id, &self.clients).await?; + let block = self.blocks.get_from_client(id, &self.clients).await?; handler::quest::quest_file_request(id, quest_file_request, &block.client_location, &mut block.rooms).await? }, RecvShipPacket::QuestChunkAck(quest_chunk_ack) => { - let block = self.blocks.from_client(id, &self.clients).await?; - handler::quest::quest_chunk_ack(id, quest_chunk_ack, &block.client_location, &mut block.rooms).await? + let block = self.blocks.get_from_client(id, &self.clients).await?; + handler::quest::quest_chunk_ack(id, quest_chunk_ack, &block.client_location, &block.rooms).await? }, RecvShipPacket::DoneLoadingQuest(_) => { - let block = self.blocks.from_client(id, &self.clients).await?; + let block = self.blocks.get_from_client(id, &self.clients).await?; handler::quest::done_loading_quest(id, &self.clients, &block.client_location).await? }, RecvShipPacket::FullCharacterData(_full_character_data) => { @@ -814,11 +727,11 @@ impl ServerState for ShipServerState { handler::ship::block_list(id, &self.name, self.blocks.0.len()) }, RecvShipPacket::ItemsToTrade(items_to_trade) => { - let block = self.blocks.from_client(id, &self.clients).await?; + let block = self.blocks.get_from_client(id, &self.clients).await?; handler::trade::items_to_trade(id, items_to_trade, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? }, RecvShipPacket::TradeConfirmed(_) => { - let block = self.blocks.from_client(id, &self.clients).await?; + let block = self.blocks.get_from_client(id, &self.clients).await?; handler::trade::trade_confirmed(id, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? }, RecvShipPacket::KeyboardConfig(keyboard_config) => { @@ -832,7 +745,7 @@ impl ServerState for ShipServerState { async fn on_disconnect(&mut self, id: ClientId) -> Result, anyhow::Error> { //let client = self.clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - let block = self.blocks.from_client(id, &self.clients).await?; + let block = self.blocks.get_from_client(id, &self.clients).await?; let area_client = block.client_location.get_local_client(id).await?; let neighbors = block.client_location.get_client_neighbors(id).await?; @@ -886,7 +799,7 @@ impl InterserverActor for ShipServerState { async fn on_connect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> { vec![ (id, ShipMessage::Authenticate(self.auth_token.clone())), - (id, ShipMessage::NewShip(Ship { + (id, ShipMessage::NewShip(Ship { name: self.name.clone(), ip: self.ip, port: self.port, @@ -896,7 +809,7 @@ impl InterserverActor for ShipServerState { ] } - async fn on_action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result, Self::Error> { + async fn on_action(&mut self, _id: ServerId, msg: Self::RecvMessage) -> Result, Self::Error> { match msg { LoginMessage::SendMail{..} => { Ok(Vec::new()) diff --git a/src/ship/shops/armor.rs b/src/ship/shops/armor.rs index b85fe12..d1d8b47 100644 --- a/src/ship/shops/armor.rs +++ b/src/ship/shops/armor.rs @@ -78,7 +78,7 @@ impl ShopItem for ArmorShopItem { armor: frame.armor, dfp: 0, evp: 0, - slots: frame.slots as u8, + slots: frame.slots, }) }, ArmorShopItem::Barrier(barrier) => { diff --git a/tests/test_exp_gain.rs b/tests/test_exp_gain.rs index 6821ad0..4584571 100644 --- a/tests/test_exp_gain.rs +++ b/tests/test_exp_gain.rs @@ -49,7 +49,7 @@ async fn test_character_gains_exp() { ship.clients.with(ClientId(1), |client| Box::pin(async move { assert!(exp == client.character.exp); - })).await; + })).await.unwrap(); } #[async_std::test] @@ -133,9 +133,9 @@ async fn test_character_levels_up_multiple_times() { assert!(matches!(levelup_pkt[1].1, SendShipPacket::Message(Message {msg: GameMessage::PlayerLevelUp(PlayerLevelUp {lvl: 8, ..})}))); - let c1 = ship.clients.with(ClientId(1), |client| Box::pin(async move { + ship.clients.with(ClientId(1), |client| Box::pin(async move { assert!(exp == client.character.exp); - })).await; + })).await.unwrap(); } #[async_std::test] From 4dc814d2446eb87f3cce4c09bf356098758b31fd Mon Sep 17 00:00:00 2001 From: jake Date: Tue, 18 Oct 2022 19:27:40 -0600 Subject: [PATCH 8/9] forgot to remove local dev libpso --- Cargo.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9a69268..391e99a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,3 @@ strum = "0.19.5" strum_macros = "0.19" anyhow = { version = "1.0.47", features = ["backtrace"] } fix-hidden-lifetime-bug = "0.2.4" - - -[patch."http://git.sharnoth.com/jake/libpso"] -libpso = { path = "../libpso" } \ No newline at end of file From 6f0fa05e3bdf86855e2c38822a2d92766e8bc662 Mon Sep 17 00:00:00 2001 From: jake Date: Tue, 18 Oct 2022 19:48:18 -0600 Subject: [PATCH 9/9] add client.rs --- src/ship/client.rs | 172 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 src/ship/client.rs diff --git a/src/ship/client.rs b/src/ship/client.rs new file mode 100644 index 0000000..795c880 --- /dev/null +++ b/src/ship/client.rs @@ -0,0 +1,172 @@ +use std::collections::HashMap; +use async_std::sync::{Arc, RwLock, RwLockReadGuard}; + +use futures::future::BoxFuture; + +use libpso::packet::ship::*; +use libpso::packet::login::Session; + +use crate::common::serverstate::ClientId; +use crate::entity::account::{UserAccountEntity, UserSettingsEntity}; +use crate::entity::character::CharacterEntity; +use crate::entity::item; + +use crate::ship::ship::ShipError; +use crate::ship::items; +use crate::ship::map::MapArea; +use crate::ship::shops::{WeaponShopItem, ToolShopItem, ArmorShopItem}; + + +#[derive(Clone, Default)] +pub struct Clients(Arc>>>); + +impl Clients { + pub async fn add(&mut self, client_id: ClientId, client_state: ClientState) { + self.0 + .write() + .await + .insert(client_id, RwLock::new(client_state)); + } + + pub async fn remove(&mut self, client_id: &ClientId) -> Option { + Some(self.0 + .write() + .await + .remove(client_id)? + .into_inner()) + } + + pub async fn with<'a, T, F>(&'a self, client_id: ClientId, func: F) -> Result + where + T: Send, + F: for<'b> FnOnce(&'b ClientState) -> BoxFuture<'b, T> + Send + 'a, + { + let clients = self.0 + .read() + .await; + let client = clients + .get(&client_id) + .ok_or_else(|| ShipError::ClientNotFound(client_id))? + .read() + .await; + + Ok(func(&client).await) + } + + pub async fn with_many<'a, T, F, const N: usize>(&'a self, client_ids: [ClientId; N], func: F) -> Result + where + T: Send, + F: for<'b> FnOnce([RwLockReadGuard<'b, ClientState>; N]) -> BoxFuture<'b, T> + Send + 'a, + { + let clients = self.0 + .read() + .await; + + let mut client_states: [std::mem::MaybeUninit>; N] = unsafe { + std::mem::MaybeUninit::uninit().assume_init() + }; + + for (cindex, client_id) in client_ids.iter().enumerate() { + let c = clients + .get(client_id) + .ok_or_else(|| ShipError::ClientNotFound(*client_id))? + .read() + .await; + client_states[cindex].write(c); + } + + let client_states = unsafe { + // TODO: this should just be a normal transmute but due to compiler limitations it + // does not yet work with const generics + // https://github.com/rust-lang/rust/issues/61956 + std::mem::transmute_copy::<_, [RwLockReadGuard; N]>(&client_states) + }; + + Ok(func(client_states).await) + } + + pub async fn with_mut<'a, T, F>(&'a self, client_id: ClientId, func: F) -> Result + where + T: Send, + F: for<'b> FnOnce(&'b mut ClientState) -> BoxFuture<'b, T> + Send + 'a, + { + let clients = self.0 + .read() + .await; + let mut client = clients + .get(&client_id) + .ok_or_else(|| ShipError::ClientNotFound(client_id))? + .write() + .await; + + Ok(func(&mut client).await) + } +} + + +#[derive(Debug, Clone, Copy)] +pub struct ItemDropLocation { + pub map_area: MapArea, + pub x: f32, + pub z: f32, + pub item_id: items::ClientItemId, +} + +pub struct LoadingQuest { + pub header_bin: Option, + pub header_dat: Option, +} + + +pub struct ClientState { + pub user: UserAccountEntity, + pub settings: UserSettingsEntity, + pub character: CharacterEntity, + _session: Session, + //guildcard: GuildCard, + pub block: usize, + pub item_drop_location: Option, + pub done_loading_quest: bool, + pub area: Option, + pub x: f32, + pub y: f32, + pub z: f32, + pub weapon_shop: Vec, + pub tool_shop: Vec, + pub armor_shop: Vec, + pub tek: Option<(items::ClientItemId, item::weapon::TekSpecialModifier, item::weapon::TekPercentModifier, i32)>, + pub character_playtime: chrono::Duration, + pub log_on_time: chrono::DateTime, +} + +impl ClientState { + pub fn new(user: UserAccountEntity, settings: UserSettingsEntity, character: CharacterEntity, session: Session) -> ClientState { + let character_playtime = chrono::Duration::seconds(character.playtime as i64); + ClientState { + user, + settings, + character, + _session: session, + block: 0, + item_drop_location: None, + done_loading_quest: false, + area: None, + x: 0.0, + y: 0.0, + z: 0.0, + weapon_shop: Vec::new(), + tool_shop: Vec::new(), + armor_shop: Vec::new(), + tek: None, + character_playtime, + log_on_time: chrono::Utc::now(), + } + } + + pub fn update_playtime(&mut self) { + let additional_playtime = chrono::Utc::now() - self.log_on_time; + self.character.playtime = (self.character_playtime + additional_playtime).num_seconds() as u32; + } +} + +