Browse Source

move interserver handler from login -> character and handle new ship messages

pbs
jake 4 years ago
parent
commit
c8059edb42
  1. 33
      src/bin/main.rs
  2. 11
      src/common/interserver.rs
  3. 3
      src/common/mainloop/interserver.rs
  4. 12
      src/common/mainloop/mod.rs
  5. 55
      src/login/character.rs
  6. 21
      src/login/login.rs
  7. 68
      src/ship/ship.rs

33
src/bin/main.rs

@ -1,3 +1,4 @@
use std::net::Ipv4Addr;
use std::time::SystemTime; use std::time::SystemTime;
use log::{info}; 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::login::LoginServerState;
use elseware::login::character::CharacterServerState; use elseware::login::character::CharacterServerState;
use elseware::ship::ship::ShipServerState; use elseware::ship::ship::ShipServerState;
use elseware::ship::ship::ShipServerStateBuilder;
use elseware::entity::account::{NewUserAccountEntity, NewUserSettingsEntity}; use elseware::entity::account::{NewUserAccountEntity, NewUserSettingsEntity};
use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; use elseware::entity::gateway::{EntityGateway, InMemoryGateway};
use elseware::entity::character::NewCharacterEntity; use elseware::entity::character::NewCharacterEntity;
@ -196,18 +198,41 @@ fn main() {
let thread_entity_gateway = entity_gateway.clone(); let thread_entity_gateway = entity_gateway.clone();
info!("[auth] starting server"); info!("[auth] starting server");
let login_state = LoginServerState::new(thread_entity_gateway); 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(); let thread_entity_gateway = entity_gateway.clone();
info!("[character] starting server"); info!("[character] starting server");
let char_state = CharacterServerState::new(thread_entity_gateway); 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(); let thread_entity_gateway = entity_gateway.clone();
info!("[ship] starting server"); 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); 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;
}); });
} }

11
src/common/interserver.rs

@ -1,17 +1,20 @@
use std::net::Ipv4Addr;
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use crate::entity::character::CharacterEntityId; 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); pub struct ServerId(pub usize);
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct AuthToken(pub String); pub struct AuthToken(pub String);
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct Ship { 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)] #[derive(Debug, Serialize, Deserialize)]

3
src/common/mainloop/interserver.rs

@ -14,7 +14,6 @@ use crate::common::mainloop::client::client_accept_mainloop;
pub use crate::common::mainloop::client::NetworkError; pub use crate::common::mainloop::client::NetworkError;
use crate::patch::patch::PatchServerState; use crate::patch::patch::PatchServerState;
use crate::login::login::LoginServerState;
use crate::login::character::CharacterServerState; use crate::login::character::CharacterServerState;
use crate::ship::ship::ShipServerState; use crate::ship::ship::ShipServerState;
use crate::entity::gateway::entitygateway::EntityGateway; use crate::entity::gateway::entitygateway::EntityGateway;
@ -181,7 +180,7 @@ where
pub fn login_listen_mainloop<EG: EntityGateway + 'static>(state: Arc<Mutex<LoginServerState<EG>>>, port: u16) -> Pin<Box<dyn Future<Output = ()>>> {
pub fn login_listen_mainloop<EG: EntityGateway + 'static>(state: Arc<Mutex<CharacterServerState<EG>>>, port: u16) -> Pin<Box<dyn Future<Output = ()>>> {
Box::pin(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), port))).await.unwrap(); 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 mut id = 0;

12
src/common/mainloop/mod.rs

@ -31,17 +31,17 @@ pub fn patch_mainloop(patch_state: PatchServerState, patch_port: u16) -> Pin<Box
Box::pin(client_mainloop) Box::pin(client_mainloop)
} }
pub fn login_mainloop<EG: EntityGateway + 'static>(login_state: LoginServerState<EG>, login_port: u16, comm_port: u16) -> Pin<Box<dyn Future<Output = ()>>> {
pub fn login_mainloop<EG: EntityGateway + 'static>(login_state: LoginServerState<EG>, login_port: u16) -> Pin<Box<dyn Future<Output = ()>>> {
let login_state = Arc::new(Mutex::new(login_state)); let login_state = Arc::new(Mutex::new(login_state));
let client_mainloop = client_accept_mainloop(login_state.clone(), login_port); 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<EG: EntityGateway + 'static>(character_state: CharacterServerState<EG>, character_port: u16) -> Pin<Box<dyn Future<Output = ()>>> {
pub fn character_mainloop<EG: EntityGateway + 'static>(character_state: CharacterServerState<EG>, character_port: u16, comm_port: u16) -> Pin<Box<dyn Future<Output = ()>>> {
let character_state = Arc::new(Mutex::new(character_state)); 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(|_| ()))
} }

55
src/login/character.rs

@ -1,6 +1,8 @@
#![allow(dead_code, unused_assignments)] #![allow(dead_code, unused_assignments)]
use std::io::Read; 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 rand::Rng;
use crc::{crc32, Hasher32}; use crc::{crc32, Hasher32};
@ -13,6 +15,7 @@ use libpso::character::character;
use crate::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; use crate::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY};
use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId};
use crate::common::interserver::{ServerId, InterserverActor, LoginMessage, ShipMessage, Ship};
use crate::common::leveltable::CharacterLevelTable; use crate::common::leveltable::CharacterLevelTable;
use libpso::{utf8_to_array, utf8_to_utf16_array}; use libpso::{utf8_to_array, utf8_to_utf16_array};
@ -162,14 +165,14 @@ impl ClientState {
} }
struct Ship {
/*struct Ship {
flags: u32, flags: u32,
name: String, name: String,
ip: [u8; 4], ip: [u8; 4],
port: u16, port: u16,
}
}*/
impl Ship {
/*impl Ship {
fn new(name: &str, ip: [u8; 4], port: u16) -> Ship { fn new(name: &str, ip: [u8; 4], port: u16) -> Ship {
Ship { Ship {
flags: 0, flags: 0,
@ -178,14 +181,14 @@ impl Ship {
port: port, port: port,
} }
} }
}
}*/
pub struct CharacterServerState<EG: EntityGateway> { pub struct CharacterServerState<EG: EntityGateway> {
entity_gateway: EG, entity_gateway: EG,
param_header: ParamDataHeader, param_header: ParamDataHeader,
param_data: Vec<u8>, param_data: Vec<u8>,
clients: HashMap<ClientId, ClientState>, clients: HashMap<ClientId, ClientState>,
ships: Vec<Ship>,
ships: BTreeMap<ServerId, Ship>,
level_table: CharacterLevelTable, level_table: CharacterLevelTable,
} }
@ -293,16 +296,16 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
pub fn new(entity_gateway: EG) -> CharacterServerState<EG> { pub fn new(entity_gateway: EG) -> CharacterServerState<EG> {
let (param_header, param_data) = generate_param_data("data/param/"); 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("Dylath-Leen", [127,0,0,1], 23424),
Ship::new("Thalarion", [127,0,0,1], 23425), Ship::new("Thalarion", [127,0,0,1], 23425),
];
];*/
CharacterServerState { CharacterServerState {
entity_gateway: entity_gateway, entity_gateway: entity_gateway,
param_header: param_header, param_header: param_header,
param_data: param_data, param_data: param_data,
clients: HashMap::new(), clients: HashMap::new(),
ships: ships,
ships: BTreeMap::new(),
level_table: CharacterLevelTable::new(), level_table: CharacterLevelTable::new(),
} }
} }
@ -326,10 +329,10 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
fn send_ship_list(&mut self, _id: ClientId, _pkt: &Login) -> Result<Vec<SendCharacterPacket>, CharacterError> { fn send_ship_list(&mut self, _id: ClientId, _pkt: &Login) -> Result<Vec<SendCharacterPacket>, CharacterError> {
Ok(vec![SendCharacterPacket::Timestamp(Timestamp::new(chrono::Utc::now())), 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 { ShipListEntry {
menu: SHIP_MENU_ID, menu: SHIP_MENU_ID,
item: i as u32,
item: i.0 as u32,
flags: 0, flags: 0,
name: utf8_to_utf16_array!(s.name, 0x11) name: utf8_to_utf16_array!(s.name, 0x11)
} }
@ -489,9 +492,9 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
return Err(CharacterError::InvalidMenuSelection(menuselect.menu, menuselect.item)); 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_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<EG: EntityGateway> ServerState for CharacterServerState<EG> {
} }
} }
#[async_trait::async_trait]
impl<EG: EntityGateway> InterserverActor for CharacterServerState<EG> {
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<Vec<(ServerId, Self::SendMessage)>, 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 { fn new_character_from_preview(user: &UserAccountEntity, preview: &CharacterPreview) -> NewCharacterEntity {
let mut character = NewCharacterEntity::new(user.id); let mut character = NewCharacterEntity::new(user.id);

21
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::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY};
use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; 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::gateway::EntityGateway;
use crate::entity::account::{UserAccountEntity}; use crate::entity::account::{UserAccountEntity};
@ -141,26 +140,6 @@ impl<EG: EntityGateway> ServerState for LoginServerState<EG> {
} }
#[async_trait::async_trait]
impl<EG: EntityGateway> InterserverActor for LoginServerState<EG> {
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<Vec<(ServerId, Self::SendMessage)>, Self::Error> {
Ok(Vec::new())
}
async fn on_disconnect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> {
Vec::new()
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use std::time::SystemTime; use std::time::SystemTime;

68
src/ship/ship.rs

@ -1,4 +1,5 @@
#![allow(dead_code, unused_must_use)] #![allow(dead_code, unused_must_use)]
use std::net::Ipv4Addr;
use std::collections::HashMap; use std::collections::HashMap;
use rand::Rng; 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::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY};
use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId};
use crate::common::leveltable::CharacterLevelTable; 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::gateway::EntityGateway;
use crate::entity::account::{UserAccountEntity, UserSettingsEntity}; use crate::entity::account::{UserAccountEntity, UserSettingsEntity};
@ -247,6 +248,58 @@ impl ClientState {
} }
} }
pub struct ShipServerStateBuilder<EG: EntityGateway> {
entity_gateway: Option<EG>,
name: Option<String>,
ip: Option<Ipv4Addr>,
port: Option<u16>,
}
impl<EG: EntityGateway> ShipServerStateBuilder<EG> {
pub fn new() -> ShipServerStateBuilder<EG> {
ShipServerStateBuilder {
entity_gateway: None,
name: None,
ip: None,
port: None,
}
}
pub fn gateway(mut self, entity_gateway: EG) -> ShipServerStateBuilder<EG> {
self.entity_gateway = Some(entity_gateway);
self
}
pub fn name(mut self, name: String) -> ShipServerStateBuilder<EG> {
self.name = Some(name);
self
}
pub fn ip(mut self, ip: Ipv4Addr) -> ShipServerStateBuilder<EG> {
self.ip = Some(ip);
self
}
pub fn port(mut self, port: u16) -> ShipServerStateBuilder<EG> {
self.port = Some(port);
self
}
pub fn build(self) -> ShipServerState<EG> {
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<EG: EntityGateway> { pub struct ShipServerState<EG: EntityGateway> {
entity_gateway: EG, entity_gateway: EG,
@ -257,10 +310,12 @@ pub struct ShipServerState<EG: EntityGateway> {
pub rooms: Rooms, pub rooms: Rooms,
item_manager: items::ItemManager, item_manager: items::ItemManager,
quests: quests::QuestList, quests: quests::QuestList,
ip: Ipv4Addr,
port: u16,
} }
impl<EG: EntityGateway> ShipServerState<EG> { impl<EG: EntityGateway> ShipServerState<EG> {
pub fn new(entity_gateway: EG) -> ShipServerState<EG> {
/*pub fn new(entity_gateway: EG) -> ShipServerState<EG> {
ShipServerState { ShipServerState {
entity_gateway: entity_gateway, entity_gateway: entity_gateway,
clients: HashMap::new(), clients: HashMap::new(),
@ -271,7 +326,7 @@ impl<EG: EntityGateway> ShipServerState<EG> {
item_manager: items::ItemManager::new(), item_manager: items::ItemManager::new(),
quests: quests::load_quests("data/quests.toml".into()).unwrap(), quests: quests::load_quests("data/quests.toml".into()).unwrap(),
} }
}
}*/
async fn message(&mut self, id: ClientId, msg: &Message) -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> { async fn message(&mut self, id: ClientId, msg: &Message) -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> {
match &msg.msg { match &msg.msg {
@ -500,7 +555,12 @@ impl<EG: EntityGateway> InterserverActor for ShipServerState<EG> {
type Error = (); type Error = ();
async fn on_connect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> { 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<Vec<(ServerId, Self::SendMessage)>, Self::Error> { async fn action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result<Vec<(ServerId, Self::SendMessage)>, Self::Error> {

Loading…
Cancel
Save