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> {