diff --git a/src/bin/main.rs b/src/bin/main.rs index 51bdf1a..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,12 +6,14 @@ 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; 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 +188,51 @@ 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); + 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::common::mainloop::mainloop_async(auth_state, elseware::login::login::LOGIN_PORT).await; - }); + 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, elseware::login::login::COMMUNICATION_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); + info!("[ship] starting server"); + 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); - elseware::common::mainloop::mainloop_async(char_state, elseware::login::character::CHARACTER_PORT).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 = 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; - }); + 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::join!(patch, auth, character, ship); + 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 new file mode 100644 index 0000000..f1110f8 --- /dev/null +++ b/src/common/interserver.rs @@ -0,0 +1,54 @@ +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, PartialOrd, Ord)] +pub struct ServerId(pub usize); +#[derive(Debug, Serialize, Deserialize)] +pub struct AuthToken(pub String); + +#[derive(Debug, Serialize, Deserialize)] +pub struct Ship { + pub name: String, + pub ip: Ipv4Addr, + pub port: u16, + pub block_count: u32, +} + +#[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 75% rename from src/common/mainloop.rs rename to src/common/mainloop/client.rs index 38a9c50..ed32e73 100644 --- a/src/common/mainloop.rs +++ b/src/common/mainloop/client.rs @@ -1,4 +1,5 @@ -#![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}; @@ -118,6 +119,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?; @@ -200,7 +202,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, { @@ -234,12 +237,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 { @@ -264,26 +266,85 @@ async fn client_send_loop(client_id: ClientId, }); } +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 async fn mainloop_async(state: STATE, port: u16) where +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, { - - 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; + 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::sync::channel(1024); - - server_state_loop(state, server_state_receiver).await; + 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); @@ -295,7 +356,6 @@ pub async fn mainloop_async(state: STATE, port: u16) 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.await + })) } + diff --git a/src/common/mainloop/interserver.rs b/src/common/mainloop/interserver.rs new file mode 100644 index 0000000..059e27e --- /dev/null +++ b/src/common/mainloop/interserver.rs @@ -0,0 +1,220 @@ +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::io::prelude::{ReadExt, WriteExt}; +use std::collections::HashMap; +use serde::Serialize; +use serde::de::DeserializeOwned; + +use crate::common::interserver::{ServerId, InterserverActor}; + +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; + + 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)?; + + let msg = serde_json::from_str(&payload).map_err(|_| MessageReceiverError::InvalidPayload)?; + Ok(msg) + } +} + +#[derive(Debug)] +enum InterserverInputAction { + NewConnection(ServerId, async_std::sync::Sender), + Message(ServerId, R), + Disconnect(ServerId), +} + +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 socket = async_std::net::TcpStream::connect((ip, port)).await.unwrap(); + id += 1; + let server_id = crate::common::interserver::ServerId(id); + let (client_sender, client_receiver) = async_std::sync::channel(64); + + info!("ship connected to login: {:?}", socket); + 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..7214ae5 --- /dev/null +++ b/src/common/mainloop/mod.rs @@ -0,0 +1,45 @@ +mod client; +mod interserver; + +use std::pin::Pin; +use futures::future::{Future, join_all, FutureExt}; +use async_std::sync::{Arc, Mutex}; + +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) -> Pin>> { + let login_state = Arc::new(Mutex::new(login_state)); + let client_mainloop = client_accept_mainloop(login_state.clone(), 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.clone(), 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.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/character.rs b/src/login/character.rs index d4b970b..1d24efa 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -1,6 +1,6 @@ #![allow(dead_code, unused_assignments)] use std::io::Read; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use rand::Rng; use crc::{crc32, Hasher32}; @@ -13,6 +13,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,37 +163,17 @@ impl ClientState { } -struct Ship { - flags: u32, - name: String, - ip: [u8; 4], - port: u16, -} - -impl Ship { - fn new(name: &str, ip: [u8; 4], port: u16) -> Ship { - Ship { - flags: 0, - name: name.to_owned(), - ip: ip, - port: port, - } - } -} - pub struct CharacterServerState { entity_gateway: EG, param_header: ParamDataHeader, param_data: Vec, clients: HashMap, - ships: Vec, + ships: BTreeMap, level_table: CharacterLevelTable, } 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)), @@ -288,21 +269,16 @@ 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, param_data: param_data, clients: HashMap::new(), - ships: ships, + ships: BTreeMap::new(), level_table: CharacterLevelTable::new(), } } @@ -326,10 +302,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 +465,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 +542,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 bbced2a..bf19f22 100644 --- a/src/login/login.rs +++ b/src/login/login.rs @@ -17,6 +17,7 @@ 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 +139,7 @@ impl ServerState for LoginServerState { } } + #[cfg(test)] mod test { use std::time::SystemTime; diff --git a/src/ship/ship.rs b/src/ship/ship.rs index a88145a..766dfcb 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,6 +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::{AuthToken, Ship, ServerId, InterserverActor, LoginMessage, ShipMessage}; use crate::entity::gateway::EntityGateway; use crate::entity::account::{UserAccountEntity, UserSettingsEntity}; @@ -246,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_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_or(Ipv4Addr::new(127,0,0,1)), + port: self.port.unwrap_or(SHIP_PORT), + } + } +} pub struct ShipServerState { entity_gateway: EG, @@ -256,20 +310,13 @@ 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 { - 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> { @@ -493,3 +540,28 @@ 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![ /* 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> { + Ok(Vec::new()) + } + + async fn on_disconnect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> { + Vec::new() + } +} 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;