From c00f851f7efdfa9f64fa5e5abaadb38deda871c7 Mon Sep 17 00:00:00 2001 From: jake Date: Thu, 13 Aug 2020 18:21:08 -0600 Subject: [PATCH 1/6] refactor mainloops --- src/bin/main.rs | 44 +++++-------- src/common/mainloop.rs | 144 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 160 insertions(+), 28 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 51bdf1a..e3a2a83 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -11,6 +11,7 @@ use elseware::entity::character::NewCharacterEntity; use elseware::entity::item::{NewItemEntity, ItemDetail, ItemLocation}; use elseware::entity::item; +use elseware::common::mainloop::*; fn setup_logger() { let colors = fern::colors::ColoredLevelConfig::new() @@ -185,39 +186,28 @@ fn main() { }).await; } - let patch = async_std::task::spawn(async { - 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); - - elseware::common::mainloop::mainloop_async(patch_state, patch_config.port).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 = patch_mainloop(patch_state, patch_config.port); let thread_entity_gateway = entity_gateway.clone(); - let auth = async_std::task::spawn(async { - info!("[auth] starting server"); - let auth_state = LoginServerState::new(thread_entity_gateway); - - elseware::common::mainloop::mainloop_async(auth_state, elseware::login::login::LOGIN_PORT).await; - }); + info!("[auth] starting server"); + let login_state = LoginServerState::new(thread_entity_gateway); + let login_loop = login_mainloop(login_state, elseware::login::login::LOGIN_PORT); let thread_entity_gateway = entity_gateway.clone(); - let character = async_std::task::spawn(async { - info!("[character] starting server"); - let char_state = CharacterServerState::new(thread_entity_gateway); - - elseware::common::mainloop::mainloop_async(char_state, elseware::login::character::CHARACTER_PORT).await; - }); + info!("[character] starting server"); + let char_state = CharacterServerState::new(thread_entity_gateway); + let character_loop = character_mainloop(char_state, elseware::login::character::CHARACTER_PORT); let thread_entity_gateway = entity_gateway.clone(); - let ship = async_std::task::spawn(async { - info!("[ship] starting server"); - let ship_state = ShipServerState::new(thread_entity_gateway); - elseware::common::mainloop::mainloop_async(ship_state, elseware::ship::ship::SHIP_PORT).await; - }); + info!("[ship] starting server"); + let ship_state = ShipServerState::new(thread_entity_gateway); + let ship_loop = ship_mainloop(ship_state, elseware::ship::ship::SHIP_PORT); - futures::join!(patch, auth, character, ship); + futures::future::join_all(vec![patch_loop, login_loop, character_loop, ship_loop]).await; }); } diff --git a/src/common/mainloop.rs b/src/common/mainloop.rs index 38a9c50..0439e0f 100644 --- a/src/common/mainloop.rs +++ b/src/common/mainloop.rs @@ -1,14 +1,24 @@ #![allow(dead_code)] +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 serde::{Serialize, Deserialize}; +use serde::de::DeserializeOwned; use libpso::crypto::{PSOCipher, NullCipher, CipherError}; use libpso::PacketParseError; use crate::common::serverstate::ClientId; use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect}; +use crate::common::interserver::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; #[derive(Debug)] pub enum NetworkError { @@ -265,7 +275,7 @@ async fn client_send_loop(client_id: ClientId, } -pub async fn mainloop_async(state: STATE, port: u16) where +pub async fn simple_mainloop(state: STATE, port: u16) where STATE: ServerState + Send + 'static, S: SendServerPacket + std::fmt::Debug + Send + Sync + 'static, R: RecvServerPacket + std::fmt::Debug + Send + Sync + 'static, @@ -299,3 +309,135 @@ pub async fn mainloop_async(state: STATE, port: u16) where listener.await } + +//////////////////////////////////////////////////////////// + + + +async fn state_client_loop(state: Arc>, + server_state_receiver: async_std::sync::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) => { + clients.insert(client_id, sender.clone()); + for action in state.on_connect(client_id) { + match action { + OnConnect::Cipher((inc, outc)) => { + sender.send(ServerStateAction::Cipher(inc, outc)).await; + }, + OnConnect::Packet(pkt) => { + sender.send(ServerStateAction::Packet(pkt)).await; + } + } + } + }, + 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; + } + } + }, + Err(err) => { + warn!("[client {:?} state handler error] {:?}", client_id, err); + } + } + }, + ClientAction::Disconnect(client_id) => { + let pkts = state.on_disconnect(client_id); + for (client_id, pkt) in pkts { + if let Some(client) = clients.get_mut(&client_id) { + client.send(ServerStateAction::Packet(pkt)).await; + } + } + + if let Some(client) = clients.get_mut(&client_id) { + client.send(ServerStateAction::Disconnect).await; + } + } + } + } + }); +} + + +pub fn client_accept_mainloop(state: Arc>, client_port: u16) -> impl Future +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, +{ + let listener = 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 = 1; + + let (server_state_sender, server_state_receiver) = async_std::sync::channel(1024); + + state_client_loop(state, server_state_receiver).await; + + loop { + let (sock, addr) = listener.accept().await.unwrap(); + let client_id = crate::common::serverstate::ClientId(id); + id += 1; + + info!("new client {:?} {:?} {:?}", client_id, sock, addr); + + let (client_sender, client_receiver) = async_std::sync::channel(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).await; + client_send_loop(client_id, socket.clone(), cipher_in.clone(), cipher_out.clone(), client_receiver).await; + } + }); + + listener +} + + + +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.clone(), login_port); + //let ship_communication_mainloop = interserver_listen_mainloop(login_state.clone(), ship_listen_port); + Box::pin(client_mainloop) +} + +pub fn character_mainloop(character_state: CharacterServerState, character_port: u16) -> Pin>> { + let character_state = Arc::new(Mutex::new(character_state)); + let client_mainloop = client_accept_mainloop(character_state, character_port); + Box::pin(client_mainloop) +} + + +pub fn ship_mainloop(ship_state: ShipServerState, ship_port: u16) -> Pin>> { + let ship_state = Arc::new(Mutex::new(ship_state)); + let client_mainloop = client_accept_mainloop(ship_state, ship_port); + //let login_mainloop = ship_to_login_mainloop(ship_state, login_port); + //let admin_mainloop = ship_admin_mainloop(ship_state, admin_port); + + //futures::future::join_all(vec![client_mainloop, login_mainloop, admin_mainloop]) + Box::pin(client_mainloop) +} From 0bb9fb1ad0412a9b20fc7424c3ad1d35c6089b09 Mon Sep 17 00:00:00 2001 From: jake Date: Thu, 13 Aug 2020 18:24:17 -0600 Subject: [PATCH 2/6] no need to set this to a var --- src/common/mainloop.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/common/mainloop.rs b/src/common/mainloop.rs index 0439e0f..09cb6a7 100644 --- a/src/common/mainloop.rs +++ b/src/common/mainloop.rs @@ -382,7 +382,7 @@ where R: RecvServerPacket + std::fmt::Debug + Send + Sync + 'static, E: std::fmt::Debug + Send, { - let listener = async_std::task::spawn(async move { + 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 = 1; @@ -405,9 +405,7 @@ where client_recv_loop(client_id, socket.clone(), cipher_in.clone(), server_state_sender.clone(), client_sender).await; client_send_loop(client_id, socket.clone(), cipher_in.clone(), cipher_out.clone(), client_receiver).await; } - }); - - listener + }) } From 2926938201589c049f5f0662bce9458b37a69280 Mon Sep 17 00:00:00 2001 From: jake Date: Wed, 19 Aug 2020 21:21:09 -0600 Subject: [PATCH 3/6] add InterserverActor trait for cross-server communication --- src/bin/main.rs | 4 +- src/common/interserver.rs | 57 +++++ .../{mainloop.rs => mainloop/client.rs} | 66 ++--- src/common/mainloop/interserver.rs | 238 ++++++++++++++++++ src/common/mainloop/mod.rs | 53 ++++ src/common/mod.rs | 1 + src/common/serverstate.rs | 1 + src/entity/character.rs | 3 +- src/login/login.rs | 23 ++ src/ship/ship.rs | 21 ++ 10 files changed, 412 insertions(+), 55 deletions(-) create mode 100644 src/common/interserver.rs rename src/common/{mainloop.rs => mainloop/client.rs} (86%) create mode 100644 src/common/mainloop/interserver.rs create mode 100644 src/common/mainloop/mod.rs diff --git a/src/bin/main.rs b/src/bin/main.rs index e3a2a83..0e23ac6 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -196,7 +196,7 @@ fn main() { let thread_entity_gateway = entity_gateway.clone(); info!("[auth] starting server"); let login_state = LoginServerState::new(thread_entity_gateway); - let login_loop = login_mainloop(login_state, elseware::login::login::LOGIN_PORT); + let login_loop = login_mainloop(login_state, elseware::login::login::LOGIN_PORT, elseware::login::login::COMMUNICATION_PORT); let thread_entity_gateway = entity_gateway.clone(); info!("[character] starting server"); @@ -206,7 +206,7 @@ fn main() { let thread_entity_gateway = entity_gateway.clone(); info!("[ship] starting server"); let ship_state = ShipServerState::new(thread_entity_gateway); - let ship_loop = ship_mainloop(ship_state, elseware::ship::ship::SHIP_PORT); + 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); futures::future::join_all(vec![patch_loop, login_loop, character_loop, ship_loop]).await; }); diff --git a/src/common/interserver.rs b/src/common/interserver.rs new file mode 100644 index 0000000..26a2d65 --- /dev/null +++ b/src/common/interserver.rs @@ -0,0 +1,57 @@ +use serde::{Serialize, Deserialize}; +use serde::de::DeserializeOwned; +use crate::entity::character::CharacterEntityId; + +#[derive(Debug, Copy, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)] +pub struct ServerId(pub usize); +#[derive(Debug, Serialize, Deserialize)] +pub struct AuthToken(pub String); + +#[derive(Debug, Serialize, Deserialize)] +pub struct Ship { + name: String, + ip: String, + port: u16, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum LoginMessage { + SendMail { + character_id: CharacterEntityId, + title: String, + message: String, + }, + ShipList { + ships: Vec, + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum ShipMessage { + Authenticate(AuthToken), + NewShip(Ship), + SendMail { + character_id: CharacterEntityId, + title: String, + message: String, + }, + RequestShipList, + +} + + + + + + + +#[async_trait::async_trait] +pub trait InterserverActor { + 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_disconnect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)>; +} diff --git a/src/common/mainloop.rs b/src/common/mainloop/client.rs similarity index 86% rename from src/common/mainloop.rs rename to src/common/mainloop/client.rs index 09cb6a7..7f037cd 100644 --- a/src/common/mainloop.rs +++ b/src/common/mainloop/client.rs @@ -1,6 +1,5 @@ -#![allow(dead_code)] use std::pin::Pin; -use futures::future::Future; +use futures::future::{Future, join_all}; use log::{trace, info, warn}; use async_std::sync::{Arc, Mutex}; use async_std::io::prelude::{ReadExt, WriteExt}; @@ -12,13 +11,7 @@ use libpso::crypto::{PSOCipher, NullCipher, CipherError}; use libpso::PacketParseError; use crate::common::serverstate::ClientId; use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect}; -use crate::common::interserver::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; #[derive(Debug)] pub enum NetworkError { @@ -128,6 +121,7 @@ async fn send_pkt(socket: Arc Result<(), NetworkError> { let buf = pkt.as_bytes(); + println!("sndbuf: {:?}", buf); let cbuf = cipher.lock().await.encrypt(&buf)?; let mut ssock = &*socket; ssock.write_all(&cbuf).await?; @@ -210,7 +204,8 @@ async fn client_recv_loop(client_id: ClientId, socket: Arc, cipher: Arc>>, server_sender: async_std::sync::Sender, R>>, - client_sender: async_std::sync::Sender>) where + client_sender: async_std::sync::Sender>) +where S: SendServerPacket + std::fmt::Debug + Send + 'static, R: RecvServerPacket + std::fmt::Debug + Send + 'static, { @@ -244,12 +239,11 @@ async fn client_recv_loop(client_id: ClientId, } async fn client_send_loop(client_id: ClientId, - socket: Arc, - cipher_in: Arc>>, - cipher_out: Arc>>, - client_receiver: async_std::sync::Receiver>, - -) where + socket: Arc, + cipher_in: Arc>>, + cipher_out: Arc>>, + client_receiver: async_std::sync::Receiver>) +where S: SendServerPacket + std::fmt::Debug + Send + 'static, { async_std::task::spawn(async move { @@ -375,25 +369,24 @@ async fn state_client_loop(state: Arc>, } -pub fn client_accept_mainloop(state: Arc>, client_port: u16) -> impl Future +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, { - async_std::task::spawn(async move { + 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 = 1; + let mut id = 0; let (server_state_sender, server_state_receiver) = async_std::sync::channel(1024); - state_client_loop(state, server_state_receiver).await; loop { let (sock, addr) = listener.accept().await.unwrap(); - let client_id = crate::common::serverstate::ClientId(id); id += 1; + let client_id = crate::common::serverstate::ClientId(id); info!("new client {:?} {:?} {:?}", client_id, sock, addr); @@ -405,37 +398,6 @@ where client_recv_loop(client_id, socket.clone(), cipher_in.clone(), server_state_sender.clone(), client_sender).await; client_send_loop(client_id, socket.clone(), cipher_in.clone(), cipher_out.clone(), client_receiver).await; } - }) + })) } - - -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.clone(), login_port); - //let ship_communication_mainloop = interserver_listen_mainloop(login_state.clone(), ship_listen_port); - Box::pin(client_mainloop) -} - -pub fn character_mainloop(character_state: CharacterServerState, character_port: u16) -> Pin>> { - let character_state = Arc::new(Mutex::new(character_state)); - let client_mainloop = client_accept_mainloop(character_state, character_port); - Box::pin(client_mainloop) -} - - -pub fn ship_mainloop(ship_state: ShipServerState, ship_port: u16) -> Pin>> { - let ship_state = Arc::new(Mutex::new(ship_state)); - let client_mainloop = client_accept_mainloop(ship_state, ship_port); - //let login_mainloop = ship_to_login_mainloop(ship_state, login_port); - //let admin_mainloop = ship_admin_mainloop(ship_state, admin_port); - - //futures::future::join_all(vec![client_mainloop, login_mainloop, admin_mainloop]) - Box::pin(client_mainloop) -} diff --git a/src/common/mainloop/interserver.rs b/src/common/mainloop/interserver.rs new file mode 100644 index 0000000..1f112da --- /dev/null +++ b/src/common/mainloop/interserver.rs @@ -0,0 +1,238 @@ +use std::time::Duration; +use std::pin::Pin; +use futures::future::{Future, join_all, FutureExt}; +use log::{trace, info, warn}; +use async_std::sync::{Arc, Mutex}; +use async_std::io::prelude::{ReadExt, WriteExt}; +use std::collections::HashMap; +use serde::{Serialize, Deserialize}; +use serde::de::DeserializeOwned; + +use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect}; +use crate::common::interserver::{ServerId, InterserverActor, LoginMessage, ShipMessage}; +use crate::common::mainloop::client::client_accept_mainloop; +pub use crate::common::mainloop::client::NetworkError; + +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; + +#[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: 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; + info!("expected len: {:?}", size); + + let mut payload = vec![0u8; size]; + self.socket.read_exact(&mut payload).await.map_err(|err| MessageReceiverError::Disconnected)?; + let payload = String::from_utf8(payload).map_err(|_| MessageReceiverError::InvalidPayload)?; + + info!("payload: {:?}", payload); + let msg = serde_json::from_str(&payload).map_err(|_| MessageReceiverError::InvalidPayload)?; + info!("msg: {:?}", msg); + Ok(msg) + } +} + + +#[derive(Debug)] +enum InterserverInputAction { + NewConnection(ServerId, async_std::sync::Sender), + Message(ServerId, R), + Disconnect(ServerId), +} + +/*struct LoginOutputAction { + Message +}*/ + +async fn interserver_state_loop(state: Arc>, action_receiver: async_std::sync::Receiver>) +where + A: InterserverActor + Send + 'static, + S: Serialize + Send + 'static, + R: DeserializeOwned + Send + 'static, +{ + async_std::task::spawn(async move { + let mut ships = HashMap::new(); + + loop { + info!("interserver loop"); + let action = action_receiver.recv().await.unwrap(); + 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; + } + } + }, + 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; + } + } + }, + Err(err) => { + warn!("[server {:?} state handler error] {:?}", server_id, err); + } + } + }, + InterserverInputAction::Disconnect(server_id) => { + let actions = state.on_disconnect(server_id).await; + for (server, action) in actions { + if let Some(sender) = ships.get_mut(&server) { + sender.send(action).await; + } + } + break; + } + } + } + }); +} + +async fn login_recv_loop(server_id: ServerId, + socket: async_std::net::TcpStream, + state_loop_sender: async_std::sync::Sender>, + output_loop_sender: async_std::sync::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; + 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 + }, + Err(err) => { + if let MessageReceiverError::Disconnected = err { + info!("[login recv loop disconnect] {:?}", server_id); + state_loop_sender.send(InterserverInputAction::Disconnect(server_id)).await; + 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::sync::Receiver) +where + S: Serialize + std::fmt::Debug + Send + 'static, +{ + async_std::task::spawn(async move { + loop { + info!("login send loop"); + let msg = output_loop_receiver.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); + + match socket.write_all(&len_bytes).await { + Ok(_) => {}, + Err(err) => warn!("send failed: {:?}", err), + } + match socket.write_all(&payload.as_bytes()).await { + Ok(_) => {}, + Err(err) => warn!("send failed: {:?}", err), + } + } + } + }); +} + + + +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::sync::channel(1024); + interserver_state_loop(state, 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::sync::channel(64); + + 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::sync::channel(1024); + interserver_state_loop(state, server_state_receiver).await; + + loop { + //let listener = async_std::net::TcpListener::bind(&std::net::SocketAddr::from((std::net::Ipv4Addr::new(0,0,0,0), port))).await.unwrap(); + // TOOD: err check and loop with timeout + let socket = async_std::net::TcpStream::connect((ip, port)).await.unwrap(); + //let (socket, addr) = listener.accept().await.unwrap(); + info!("ship connected to login: {:?}", socket); + + id += 1; + let server_id = crate::common::interserver::ServerId(id); + + let (client_sender, client_receiver) = async_std::sync::channel(64); + + login_recv_loop(server_id, socket.clone(), server_state_sender.clone(), client_sender).await; + interserver_send_loop(server_id, socket.clone(), client_receiver).await; + loop { + if let Err(_) = socket.peer_addr() { + info!("ship connected to login: {:?}", socket); + break; + } + async_std::task::sleep(Duration::from_secs(10)).await; + } + } + })) +} + diff --git a/src/common/mainloop/mod.rs b/src/common/mainloop/mod.rs new file mode 100644 index 0000000..31c41e7 --- /dev/null +++ b/src/common/mainloop/mod.rs @@ -0,0 +1,53 @@ +mod client; +mod interserver; + +use std::time::Duration; +use std::pin::Pin; +use futures::future::{Future, join_all, FutureExt}; +use log::{trace, info, warn}; +use async_std::sync::{Arc, Mutex}; +use async_std::io::prelude::{ReadExt, WriteExt}; +use std::collections::HashMap; +use serde::{Serialize, Deserialize}; +use serde::de::DeserializeOwned; + +use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect}; +use crate::common::interserver::{ServerId, InterserverActor, LoginMessage, ShipMessage}; +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::patch::patch::PatchServerState; +use crate::login::login::LoginServerState; +use crate::login::character::CharacterServerState; +use crate::ship::ship::ShipServerState; +use crate::entity::gateway::entitygateway::EntityGateway; + + + +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, comm_port: u16) -> Pin>> { + let login_state = Arc::new(Mutex::new(login_state)); + let client_mainloop = client_accept_mainloop(login_state.clone(), login_port); + let ship_communication_mainloop = login_listen_mainloop(login_state.clone(), comm_port); + Box::pin(join_all(vec![client_mainloop, ship_communication_mainloop]).map(|_| ())) +} + +pub fn character_mainloop(character_state: CharacterServerState, character_port: u16) -> Pin>> { + let character_state = Arc::new(Mutex::new(character_state)); + let client_mainloop = client_accept_mainloop(character_state, character_port); + Box::pin(client_mainloop) +} + + +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.clone(), comm_ip, comm_port); + Box::pin(join_all(vec![client_mainloop, login_communication_mainloop]).map(|_| ())) +} diff --git a/src/common/mod.rs b/src/common/mod.rs index 954e8d0..d02076e 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -2,6 +2,7 @@ pub mod cipherkeys; pub mod serverstate; pub mod mainloop; pub mod leveltable; +pub mod interserver; // https://www.reddit.com/r/rust/comments/33xhhu/how_to_create_an_array_of_structs_that_havent/ #[macro_export] diff --git a/src/common/serverstate.rs b/src/common/serverstate.rs index 8417f7a..f1573ae 100644 --- a/src/common/serverstate.rs +++ b/src/common/serverstate.rs @@ -17,6 +17,7 @@ pub trait SendServerPacket: Sized + Sync { fn as_bytes(&self) -> Vec; } +// 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 { type SendPacket: SendServerPacket; diff --git a/src/entity/character.rs b/src/entity/character.rs index f146998..fc87569 100644 --- a/src/entity/character.rs +++ b/src/entity/character.rs @@ -1,5 +1,6 @@ use std::convert::{From, Into}; use std::collections::HashMap; +use serde::{Serialize, Deserialize}; use libpso::packet::ship::{UpdateConfig, WriteInfoboard}; use libpso::character::character::{DEFAULT_PALETTE_CONFIG, DEFAULT_TECH_MENU}; @@ -235,7 +236,7 @@ pub struct CharacterMaterials { pub tp: u32, } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] pub struct CharacterEntityId(pub u32); #[derive(Clone)] diff --git a/src/login/login.rs b/src/login/login.rs index bbced2a..3c2e21a 100644 --- a/src/login/login.rs +++ b/src/login/login.rs @@ -12,11 +12,13 @@ use libpso::util::array_to_utf8; 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}; use crate::entity::gateway::EntityGateway; use crate::entity::account::{UserAccountEntity}; pub const LOGIN_PORT: u16 = 12000; +pub const COMMUNICATION_PORT: u16 = 12123; #[derive(Debug)] pub enum LoginError { @@ -138,6 +140,27 @@ impl ServerState for LoginServerState { } } + +#[async_trait::async_trait] +impl InterserverActor for LoginServerState { + type SendMessage = LoginMessage; + type RecvMessage = ShipMessage; + type Error = (); + + async fn on_connect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> { + Vec::new() + } + + async fn action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result, Self::Error> { + Ok(Vec::new()) + } + + async fn on_disconnect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> { + Vec::new() + } +} + + #[cfg(test)] mod test { use std::time::SystemTime; diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 69c0870..91341ca 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -15,6 +15,7 @@ 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::leveltable::CharacterLevelTable; +use crate::common::interserver::{ServerId, InterserverActor, LoginMessage, ShipMessage}; use crate::entity::gateway::EntityGateway; use crate::entity::account::{UserAccountEntity, UserSettingsEntity}; @@ -490,3 +491,23 @@ impl ServerState for ShipServerState { }).collect() } } + + +#[async_trait::async_trait] +impl InterserverActor for ShipServerState { + type SendMessage = ShipMessage; + type RecvMessage = LoginMessage; + type Error = (); + + async fn on_connect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> { + Vec::new() + } + + async fn action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result, Self::Error> { + Ok(Vec::new()) + } + + async fn on_disconnect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> { + Vec::new() + } +} From c8059edb42be1c4a600b02b2913a5b9eca906a85 Mon Sep 17 00:00:00 2001 From: jake Date: Wed, 19 Aug 2020 23:18:04 -0600 Subject: [PATCH 4/6] move interserver handler from login -> character and handle new ship messages --- src/bin/main.rs | 33 +++++++++++++-- src/common/interserver.rs | 11 +++-- src/common/mainloop/interserver.rs | 3 +- src/common/mainloop/mod.rs | 12 +++--- src/login/character.rs | 55 ++++++++++++++++++------ src/login/login.rs | 21 --------- src/ship/ship.rs | 68 ++++++++++++++++++++++++++++-- 7 files changed, 149 insertions(+), 54 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 0e23ac6..f83f88f 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,3 +1,4 @@ +use std::net::Ipv4Addr; use std::time::SystemTime; use log::{info}; @@ -5,6 +6,7 @@ use elseware::patch::patch::{PatchServerState, generate_patch_tree, load_config, use elseware::login::login::LoginServerState; use elseware::login::character::CharacterServerState; use elseware::ship::ship::ShipServerState; +use elseware::ship::ship::ShipServerStateBuilder; use elseware::entity::account::{NewUserAccountEntity, NewUserSettingsEntity}; use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; use elseware::entity::character::NewCharacterEntity; @@ -196,18 +198,41 @@ fn main() { let thread_entity_gateway = entity_gateway.clone(); info!("[auth] starting server"); let login_state = LoginServerState::new(thread_entity_gateway); - let login_loop = login_mainloop(login_state, elseware::login::login::LOGIN_PORT, elseware::login::login::COMMUNICATION_PORT); + 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 = CharacterServerState::new(thread_entity_gateway); - let character_loop = character_mainloop(char_state, elseware::login::character::CHARACTER_PORT); + 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 = ShipServerState::new(thread_entity_gateway); + let ship_state = ShipServerStateBuilder::new() + .name("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); - futures::future::join_all(vec![patch_loop, login_loop, character_loop, ship_loop]).await; + let thread_entity_gateway = entity_gateway.clone(); + let ship_state = ShipServerStateBuilder::new() + .name("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 = ShipServerStateBuilder::new() + .name("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; }); } diff --git a/src/common/interserver.rs b/src/common/interserver.rs index 26a2d65..2f1c494 100644 --- a/src/common/interserver.rs +++ b/src/common/interserver.rs @@ -1,17 +1,20 @@ +use std::net::Ipv4Addr; use serde::{Serialize, Deserialize}; use serde::de::DeserializeOwned; use crate::entity::character::CharacterEntityId; -#[derive(Debug, Copy, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct ServerId(pub usize); #[derive(Debug, Serialize, Deserialize)] pub struct AuthToken(pub String); #[derive(Debug, Serialize, Deserialize)] pub struct Ship { - name: String, - ip: String, - port: u16, + pub name: String, + //pub ip: String, + pub ip: Ipv4Addr, + pub port: u16, + pub block_count: u32, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/common/mainloop/interserver.rs b/src/common/mainloop/interserver.rs index 1f112da..fbc0a47 100644 --- a/src/common/mainloop/interserver.rs +++ b/src/common/mainloop/interserver.rs @@ -14,7 +14,6 @@ use crate::common::mainloop::client::client_accept_mainloop; pub use crate::common::mainloop::client::NetworkError; 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; @@ -181,7 +180,7 @@ where -pub fn login_listen_mainloop(state: Arc>>, port: u16) -> Pin>> { +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; diff --git a/src/common/mainloop/mod.rs b/src/common/mainloop/mod.rs index 31c41e7..48fc631 100644 --- a/src/common/mainloop/mod.rs +++ b/src/common/mainloop/mod.rs @@ -31,17 +31,17 @@ pub fn patch_mainloop(patch_state: PatchServerState, patch_port: u16) -> Pin(login_state: LoginServerState, login_port: u16, comm_port: u16) -> Pin>> { +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.clone(), login_port); - let ship_communication_mainloop = login_listen_mainloop(login_state.clone(), comm_port); - Box::pin(join_all(vec![client_mainloop, ship_communication_mainloop]).map(|_| ())) + Box::pin(client_mainloop) } -pub fn character_mainloop(character_state: CharacterServerState, character_port: u16) -> Pin>> { +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, character_port); - Box::pin(client_mainloop) + let client_mainloop = client_accept_mainloop(character_state.clone(), character_port); + let ship_communication_mainloop = login_listen_mainloop(character_state.clone(), comm_port); + Box::pin(join_all(vec![client_mainloop, ship_communication_mainloop]).map(|_| ())) } diff --git a/src/login/character.rs b/src/login/character.rs index d4b970b..7a45fcf 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -1,6 +1,8 @@ #![allow(dead_code, unused_assignments)] use std::io::Read; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; +use std::net::Ipv4Addr; +use std::str::FromStr; use rand::Rng; use crc::{crc32, Hasher32}; @@ -13,6 +15,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 libpso::{utf8_to_array, utf8_to_utf16_array}; @@ -162,14 +165,14 @@ impl ClientState { } -struct Ship { +/*struct Ship { flags: u32, name: String, ip: [u8; 4], port: u16, -} +}*/ -impl Ship { +/*impl Ship { fn new(name: &str, ip: [u8; 4], port: u16) -> Ship { Ship { flags: 0, @@ -178,14 +181,14 @@ impl Ship { port: port, } } -} +}*/ pub struct CharacterServerState { entity_gateway: EG, param_header: ParamDataHeader, param_data: Vec, clients: HashMap, - ships: Vec, + ships: BTreeMap, level_table: CharacterLevelTable, } @@ -293,16 +296,16 @@ impl CharacterServerState { pub fn new(entity_gateway: EG) -> CharacterServerState { let (param_header, param_data) = generate_param_data("data/param/"); - let ships = vec![Ship::new("Sona-Nyl", [127,0,0,1], 23423), + /*let ships = vec![Ship::new("Sona-Nyl", [127,0,0,1], 23423), Ship::new("Dylath-Leen", [127,0,0,1], 23424), Ship::new("Thalarion", [127,0,0,1], 23425), - ]; + ];*/ CharacterServerState { entity_gateway: entity_gateway, param_header: param_header, param_data: param_data, clients: HashMap::new(), - ships: ships, + ships: BTreeMap::new(), level_table: CharacterLevelTable::new(), } } @@ -326,10 +329,10 @@ impl CharacterServerState { fn send_ship_list(&mut self, _id: ClientId, _pkt: &Login) -> Result, CharacterError> { Ok(vec![SendCharacterPacket::Timestamp(Timestamp::new(chrono::Utc::now())), - SendCharacterPacket::ShipList(ShipList::new(self.ships.iter().enumerate().map(|(i, s)| { + SendCharacterPacket::ShipList(ShipList::new(self.ships.iter().map(|(i, s)| { ShipListEntry { menu: SHIP_MENU_ID, - item: i as u32, + item: i.0 as u32, flags: 0, name: utf8_to_utf16_array!(s.name, 0x11) } @@ -489,9 +492,9 @@ impl CharacterServerState { return Err(CharacterError::InvalidMenuSelection(menuselect.menu, menuselect.item)); } - let ship = self.ships.get(menuselect.item as usize) + let ship = self.ships.get(&ServerId(menuselect.item as usize)) .ok_or(CharacterError::InvalidMenuSelection(menuselect.menu, menuselect.item))?; - Ok(vec![SendCharacterPacket::RedirectClient(RedirectClient::new(u32::from_le_bytes(ship.ip), ship.port))]) + Ok(vec![SendCharacterPacket::RedirectClient(RedirectClient::new(u32::from_le_bytes(ship.ip.octets()), ship.port))]) } } @@ -566,6 +569,32 @@ impl ServerState for CharacterServerState { } } +#[async_trait::async_trait] +impl InterserverActor for CharacterServerState { + type SendMessage = LoginMessage; + type RecvMessage = ShipMessage; + type Error = (); + + async fn on_connect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> { + Vec::new() + } + + async fn action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result, Self::Error> { + match msg { + ShipMessage::Authenticate(auth_token) => {}, + ShipMessage::NewShip(new_ship) => { + self.ships.insert(id, new_ship); + }, + _ => {} + } + Ok(Vec::new()) + } + + async fn on_disconnect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> { + Vec::new() + } +} + fn new_character_from_preview(user: &UserAccountEntity, preview: &CharacterPreview) -> NewCharacterEntity { let mut character = NewCharacterEntity::new(user.id); diff --git a/src/login/login.rs b/src/login/login.rs index 3c2e21a..bf19f22 100644 --- a/src/login/login.rs +++ b/src/login/login.rs @@ -12,7 +12,6 @@ use libpso::util::array_to_utf8; 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}; use crate::entity::gateway::EntityGateway; use crate::entity::account::{UserAccountEntity}; @@ -141,26 +140,6 @@ impl ServerState for LoginServerState { } -#[async_trait::async_trait] -impl InterserverActor for LoginServerState { - type SendMessage = LoginMessage; - type RecvMessage = ShipMessage; - type Error = (); - - async fn on_connect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> { - Vec::new() - } - - async fn action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result, Self::Error> { - Ok(Vec::new()) - } - - async fn on_disconnect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> { - Vec::new() - } -} - - #[cfg(test)] mod test { use std::time::SystemTime; diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 91341ca..89f8e08 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -1,4 +1,5 @@ #![allow(dead_code, unused_must_use)] +use std::net::Ipv4Addr; use std::collections::HashMap; use rand::Rng; @@ -15,7 +16,7 @@ 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::leveltable::CharacterLevelTable; -use crate::common::interserver::{ServerId, InterserverActor, LoginMessage, ShipMessage}; +use crate::common::interserver::{AuthToken, Ship, ServerId, InterserverActor, LoginMessage, ShipMessage}; use crate::entity::gateway::EntityGateway; use crate::entity::account::{UserAccountEntity, UserSettingsEntity}; @@ -247,6 +248,58 @@ impl ClientState { } } +pub struct ShipServerStateBuilder { + entity_gateway: Option, + name: Option, + ip: Option, + port: Option, +} + +impl ShipServerStateBuilder { + pub fn new() -> ShipServerStateBuilder { + ShipServerStateBuilder { + entity_gateway: None, + name: None, + ip: None, + port: None, + } + } + + pub fn gateway(mut self, entity_gateway: EG) -> ShipServerStateBuilder { + self.entity_gateway = Some(entity_gateway); + self + } + + pub fn name(mut self, name: String) -> ShipServerStateBuilder { + self.name = Some(name); + self + } + + pub fn ip(mut self, ip: Ipv4Addr) -> ShipServerStateBuilder { + self.ip = Some(ip); + self + } + + pub fn port(mut self, port: u16) -> ShipServerStateBuilder { + self.port = Some(port); + self + } + + pub fn build(self) -> ShipServerState { + ShipServerState { + entity_gateway: self.entity_gateway.unwrap(), + clients: HashMap::new(), + client_location: ClientLocation::new(), + level_table: CharacterLevelTable::new(), + name: self.name.unwrap(), + rooms: [None; MAX_ROOMS], + item_manager: items::ItemManager::new(), + quests: quests::load_quests("data/quests.toml".into()).unwrap(), + ip: self.ip.unwrap(), + port: self.port.unwrap(), + } + } +} pub struct ShipServerState { entity_gateway: EG, @@ -257,10 +310,12 @@ pub struct ShipServerState { pub rooms: Rooms, item_manager: items::ItemManager, quests: quests::QuestList, + ip: Ipv4Addr, + port: u16, } impl ShipServerState { - pub fn new(entity_gateway: EG) -> ShipServerState { + /*pub fn new(entity_gateway: EG) -> ShipServerState { ShipServerState { entity_gateway: entity_gateway, clients: HashMap::new(), @@ -271,7 +326,7 @@ impl ShipServerState { item_manager: items::ItemManager::new(), quests: quests::load_quests("data/quests.toml".into()).unwrap(), } - } + }*/ async fn message(&mut self, id: ClientId, msg: &Message) -> Result + Send>, ShipError> { match &msg.msg { @@ -500,7 +555,12 @@ impl InterserverActor for ShipServerState { type Error = (); async fn on_connect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> { - Vec::new() + vec![ /* ShipMessage::Authenticate(AuthToken("hi".into())), */ (id, ShipMessage::NewShip(Ship { + name: self.name.clone(), + ip: self.ip.clone(), + port: self.port, + block_count: 2, + })) ] } async fn action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result, Self::Error> { From 317acad564aefab7f8379543c8e830caf663185a Mon Sep 17 00:00:00 2001 From: jake Date: Thu, 20 Aug 2020 09:37:18 -0600 Subject: [PATCH 5/6] cleanup --- src/common/interserver.rs | 6 ---- src/common/mainloop/client.rs | 44 +----------------------------- src/common/mainloop/interserver.rs | 31 +++++---------------- src/common/mainloop/mod.rs | 8 ------ src/login/character.rs | 29 +------------------- 5 files changed, 9 insertions(+), 109 deletions(-) diff --git a/src/common/interserver.rs b/src/common/interserver.rs index 2f1c494..f1110f8 100644 --- a/src/common/interserver.rs +++ b/src/common/interserver.rs @@ -11,7 +11,6 @@ pub struct AuthToken(pub String); #[derive(Debug, Serialize, Deserialize)] pub struct Ship { pub name: String, - //pub ip: String, pub ip: Ipv4Addr, pub port: u16, pub block_count: u32, @@ -43,11 +42,6 @@ pub enum ShipMessage { } - - - - - #[async_trait::async_trait] pub trait InterserverActor { type SendMessage: Serialize; diff --git a/src/common/mainloop/client.rs b/src/common/mainloop/client.rs index 7f037cd..ed32e73 100644 --- a/src/common/mainloop/client.rs +++ b/src/common/mainloop/client.rs @@ -1,11 +1,9 @@ use std::pin::Pin; -use futures::future::{Future, join_all}; +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 serde::{Serialize, Deserialize}; -use serde::de::DeserializeOwned; use libpso::crypto::{PSOCipher, NullCipher, CipherError}; use libpso::PacketParseError; @@ -268,46 +266,6 @@ where }); } - -pub async fn simple_mainloop(state: STATE, port: u16) 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, -{ - - let listener = 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 = 1; - - let (server_state_sender, server_state_receiver) = async_std::sync::channel(1024); - - server_state_loop(state, server_state_receiver).await; - - loop { - let (sock, addr) = listener.accept().await.unwrap(); - let client_id = crate::common::serverstate::ClientId(id); - id += 1; - - info!("new client {:?} {:?} {:?}", client_id, sock, addr); - - let (client_sender, client_receiver) = async_std::sync::channel(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).await; - client_send_loop(client_id, socket.clone(), cipher_in.clone(), cipher_out.clone(), client_receiver).await; - } - }); - - listener.await -} - -//////////////////////////////////////////////////////////// - - - async fn state_client_loop(state: Arc>, server_state_receiver: async_std::sync::Receiver, R>>) where STATE: ServerState + Send + 'static, diff --git a/src/common/mainloop/interserver.rs b/src/common/mainloop/interserver.rs index fbc0a47..059e27e 100644 --- a/src/common/mainloop/interserver.rs +++ b/src/common/mainloop/interserver.rs @@ -1,28 +1,24 @@ use std::time::Duration; use std::pin::Pin; -use futures::future::{Future, join_all, FutureExt}; -use log::{trace, info, warn}; +use futures::future::Future; +use log::{info, warn}; use async_std::sync::{Arc, Mutex}; use async_std::io::prelude::{ReadExt, WriteExt}; use std::collections::HashMap; -use serde::{Serialize, Deserialize}; +use serde::Serialize; use serde::de::DeserializeOwned; -use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect}; -use crate::common::interserver::{ServerId, InterserverActor, LoginMessage, ShipMessage}; -use crate::common::mainloop::client::client_accept_mainloop; -pub use crate::common::mainloop::client::NetworkError; +use crate::common::interserver::{ServerId, InterserverActor}; -use crate::patch::patch::PatchServerState; use crate::login::character::CharacterServerState; use crate::ship::ship::ShipServerState; use crate::entity::gateway::entitygateway::EntityGateway; #[derive(Debug)] enum MessageReceiverError { - InvalidSize, + //InvalidSize, InvalidPayload, - NetworkError(std::io::Error), + //NetworkError(std::io::Error), Disconnected, } @@ -41,20 +37,16 @@ impl MessageReceiver { 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; - info!("expected len: {:?}", size); let mut payload = vec![0u8; size]; self.socket.read_exact(&mut payload).await.map_err(|err| MessageReceiverError::Disconnected)?; let payload = String::from_utf8(payload).map_err(|_| MessageReceiverError::InvalidPayload)?; - info!("payload: {:?}", payload); let msg = serde_json::from_str(&payload).map_err(|_| MessageReceiverError::InvalidPayload)?; - info!("msg: {:?}", msg); Ok(msg) } } - #[derive(Debug)] enum InterserverInputAction { NewConnection(ServerId, async_std::sync::Sender), @@ -62,10 +54,6 @@ enum InterserverInputAction { Disconnect(ServerId), } -/*struct LoginOutputAction { - Message -}*/ - async fn interserver_state_loop(state: Arc>, action_receiver: async_std::sync::Receiver>) where A: InterserverActor + Send + 'static, @@ -211,17 +199,12 @@ pub fn ship_connect_mainloop(state: Arc Ship { - Ship { - flags: 0, - name: name.to_owned(), - ip: ip, - port: port, - } - } -}*/ - pub struct CharacterServerState { entity_gateway: EG, param_header: ParamDataHeader, @@ -194,8 +174,6 @@ pub struct CharacterServerState { async fn new_character(entity_gateway: &mut EG, user: &UserAccountEntity, preview: &CharacterPreview) { - //let mut character = entity_gateway.new_character_by_user(&user); - //new_character_from_preview(&mut char, preview); 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)), @@ -291,15 +269,10 @@ async fn new_character(entity_gateway: &mut EG, user: &UserAc } - impl CharacterServerState { pub fn new(entity_gateway: EG) -> CharacterServerState { let (param_header, param_data) = generate_param_data("data/param/"); - /*let ships = vec![Ship::new("Sona-Nyl", [127,0,0,1], 23423), - Ship::new("Dylath-Leen", [127,0,0,1], 23424), - Ship::new("Thalarion", [127,0,0,1], 23425), - ];*/ CharacterServerState { entity_gateway: entity_gateway, param_header: param_header, @@ -581,7 +554,7 @@ impl InterserverActor for CharacterServerState { async fn action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result, Self::Error> { match msg { - ShipMessage::Authenticate(auth_token) => {}, + ShipMessage::Authenticate(_auth_token) => {}, ShipMessage::NewShip(new_ship) => { self.ships.insert(id, new_ship); }, From 982966e679b8ed95fede782aad0b4131a4cb0861 Mon Sep 17 00:00:00 2001 From: jake Date: Thu, 20 Aug 2020 11:52:12 -0600 Subject: [PATCH 6/6] fix tests --- src/ship/ship.rs | 21 +++----- tests/test_bank.rs | 104 ++++++++++++++++++++++++++++---------- tests/test_exp_gain.rs | 16 ++++-- tests/test_item_pickup.rs | 40 +++++++++++---- tests/test_item_use.rs | 20 ++++++-- 5 files changed, 141 insertions(+), 60 deletions(-) diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 89f8e08..b58c052 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -291,12 +291,12 @@ impl ShipServerStateBuilder { clients: HashMap::new(), client_location: ClientLocation::new(), level_table: CharacterLevelTable::new(), - name: self.name.unwrap(), + name: self.name.unwrap_or("NAMENOTSET".into()), rooms: [None; MAX_ROOMS], item_manager: items::ItemManager::new(), quests: quests::load_quests("data/quests.toml".into()).unwrap(), - ip: self.ip.unwrap(), - port: self.port.unwrap(), + ip: self.ip.unwrap_or(Ipv4Addr::new(127,0,0,1)), + port: self.port.unwrap_or(SHIP_PORT), } } } @@ -315,18 +315,9 @@ pub struct ShipServerState { } impl ShipServerState { - /*pub fn new(entity_gateway: EG) -> ShipServerState { - ShipServerState { - entity_gateway: entity_gateway, - clients: HashMap::new(), - client_location: ClientLocation::new(), - level_table: CharacterLevelTable::new(), - name: "Sona-Nyl".into(), - rooms: [None; MAX_ROOMS], - item_manager: items::ItemManager::new(), - quests: quests::load_quests("data/quests.toml".into()).unwrap(), - } - }*/ + pub fn builder() -> ShipServerStateBuilder { + ShipServerStateBuilder::new() + } async fn message(&mut self, id: ClientId, msg: &Message) -> Result + Send>, ShipError> { match &msg.msg { diff --git a/tests/test_bank.rs b/tests/test_bank.rs index eb93867..99318f6 100644 --- a/tests/test_bank.rs +++ b/tests/test_bank.rs @@ -34,7 +34,9 @@ async fn test_bank_items_sent_in_character_login() { } }).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; let packets = ship.handle(ClientId(1), &RecvShipPacket::MenuSelect(MenuSelect { @@ -71,7 +73,9 @@ async fn test_request_bank_items() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -114,7 +118,9 @@ async fn test_request_stacked_bank_items() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -186,7 +192,9 @@ async fn test_request_bank_items_sorted() { } }).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -249,7 +257,9 @@ async fn test_deposit_individual_item() { } }).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -316,7 +326,9 @@ async fn test_deposit_stacked_item() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -383,7 +395,9 @@ async fn test_deposit_partial_stacked_item() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -476,7 +490,9 @@ async fn test_deposit_stacked_item_with_stack_already_in_bank() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -557,7 +573,9 @@ async fn test_deposit_stacked_item_with_full_stack_in_bank() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -649,7 +667,9 @@ async fn test_deposit_individual_item_in_full_bank() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -739,7 +759,9 @@ async fn test_deposit_stacked_item_in_full_bank() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -844,7 +866,9 @@ async fn test_deposit_stacked_item_in_full_bank_with_partial_stack() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -899,7 +923,9 @@ async fn test_deposit_meseta() { char1.meseta = 300; entity_gateway.save_character(&char1).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -935,7 +961,9 @@ async fn test_deposit_too_much_meseta() { char1.bank_meseta = 999980; entity_gateway.save_character(&char1).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -972,7 +1000,9 @@ async fn test_deposit_meseta_when_bank_is_maxed() { char1.bank_meseta = 999999; entity_gateway.save_character(&char1).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1024,7 +1054,9 @@ async fn test_withdraw_individual_item() { } }).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -1089,7 +1121,9 @@ async fn test_withdraw_stacked_item() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -1154,7 +1188,9 @@ async fn test_withdraw_partial_stacked_item() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -1245,7 +1281,9 @@ async fn test_withdraw_stacked_item_with_stack_already_in_inventory() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -1325,7 +1363,9 @@ async fn test_withdraw_stacked_item_with_full_stack_in_inventory() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1417,7 +1457,9 @@ async fn test_withdraw_individual_item_in_full_inventory() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1507,7 +1549,9 @@ async fn test_withdraw_stacked_item_in_full_inventory() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1613,7 +1657,9 @@ async fn test_withdraw_stacked_item_in_full_inventory_with_partial_stack() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1668,7 +1714,9 @@ async fn test_withdraw_meseta() { char1.bank_meseta = 300; entity_gateway.save_character(&char1).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1704,7 +1752,9 @@ async fn test_withdraw_too_much_meseta() { char1.bank_meseta = 300; entity_gateway.save_character(&char1).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -1740,7 +1790,9 @@ async fn test_withdraw_meseta_inventory_is_maxed() { char1.bank_meseta = 300; entity_gateway.save_character(&char1).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; diff --git a/tests/test_exp_gain.rs b/tests/test_exp_gain.rs index 3b26c05..192ad3f 100644 --- a/tests/test_exp_gain.rs +++ b/tests/test_exp_gain.rs @@ -17,7 +17,9 @@ async fn test_character_gains_exp() { let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -54,7 +56,9 @@ async fn test_character_levels_up() { char1.exp = 49; entity_gateway.save_character(&char1).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -90,7 +94,9 @@ async fn test_character_levels_up_multiple_times() { let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -133,7 +139,9 @@ async fn test_one_character_gets_full_exp_and_other_attacker_gets_partial() { let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a").await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; diff --git a/tests/test_item_pickup.rs b/tests/test_item_pickup.rs index 97146f2..2b584c4 100644 --- a/tests/test_item_pickup.rs +++ b/tests/test_item_pickup.rs @@ -49,7 +49,9 @@ async fn test_pick_up_item_stack_of_items_already_in_inventory() { } } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -116,7 +118,9 @@ async fn test_pick_up_item_stack_of_items_not_already_held() { } }).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -185,7 +189,9 @@ async fn test_pick_up_meseta_when_inventory_full() { char2.meseta = 300; entity_gateway.save_character(&char2).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -285,7 +291,9 @@ async fn test_pick_up_partial_stacked_item_when_inventory_is_otherwise_full() { } }).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -372,7 +380,9 @@ async fn test_can_not_pick_up_item_when_inventory_full() { } }).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -428,7 +438,9 @@ async fn test_can_not_drop_more_meseta_than_is_held() { char1.meseta = 300; entity_gateway.save_character(&char1).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; @@ -496,7 +508,9 @@ async fn test_pick_up_stack_that_would_exceed_stack_limit() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -545,7 +559,9 @@ async fn test_can_not_pick_up_meseta_when_full() { char2.meseta = 300; entity_gateway.save_character(&char2).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -601,7 +617,9 @@ async fn test_meseta_caps_at_999999_when_trying_to_pick_up_more() { char2.meseta = 300; entity_gateway.save_character(&char2).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -667,7 +685,9 @@ async fn test_player_drops_partial_stack_and_other_player_picks_it_up() { }).await; } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; diff --git a/tests/test_item_use.rs b/tests/test_item_use.rs index a84afef..297a5e3 100644 --- a/tests/test_item_use.rs +++ b/tests/test_item_use.rs @@ -36,7 +36,9 @@ async fn test_use_monomate() { } } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -90,7 +92,9 @@ async fn test_use_monomate_twice() { } } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -149,7 +153,9 @@ async fn test_use_last_monomate() { } } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -199,7 +205,9 @@ async fn test_use_nonstackable_tool() { } }).await; - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; @@ -238,7 +246,9 @@ async fn test_use_materials() { } } - let mut ship = ShipServerState::new(entity_gateway.clone()); + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await;