Merge pull request 'interserver communication' (#202) from interserver_communication into master
This commit is contained in:
commit
431752cbf7
@ -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);
|
||||
|
||||
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, 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;
|
||||
});
|
||||
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);
|
||||
|
||||
futures::join!(patch, auth, character, ship);
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
54
src/common/interserver.rs
Normal file
54
src/common/interserver.rs
Normal file
@ -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<Ship>,
|
||||
}
|
||||
}
|
||||
|
||||
#[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<Vec<(ServerId, Self::SendMessage)>, Self::Error>;
|
||||
async fn on_disconnect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)>;
|
||||
}
|
@ -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<S: SendServerPacket + Send + std::fmt::Debug>(socket: Arc<asyn
|
||||
-> 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<S, R>(client_id: ClientId,
|
||||
socket: Arc<async_std::net::TcpStream>,
|
||||
cipher: Arc<Mutex<Box<dyn PSOCipher + Send>>>,
|
||||
server_sender: async_std::sync::Sender<ClientAction<ServerStateAction<S>, R>>,
|
||||
client_sender: async_std::sync::Sender<ServerStateAction<S>>) where
|
||||
client_sender: async_std::sync::Sender<ServerStateAction<S>>)
|
||||
where
|
||||
S: SendServerPacket + std::fmt::Debug + Send + 'static,
|
||||
R: RecvServerPacket + std::fmt::Debug + Send + 'static,
|
||||
{
|
||||
@ -234,12 +237,11 @@ async fn client_recv_loop<S, R>(client_id: ClientId,
|
||||
}
|
||||
|
||||
async fn client_send_loop<S>(client_id: ClientId,
|
||||
socket: Arc<async_std::net::TcpStream>,
|
||||
cipher_in: Arc<Mutex<Box<dyn PSOCipher + Send>>>,
|
||||
cipher_out: Arc<Mutex<Box<dyn PSOCipher + Send>>>,
|
||||
client_receiver: async_std::sync::Receiver<ServerStateAction<S>>,
|
||||
|
||||
) where
|
||||
socket: Arc<async_std::net::TcpStream>,
|
||||
cipher_in: Arc<Mutex<Box<dyn PSOCipher + Send>>>,
|
||||
cipher_out: Arc<Mutex<Box<dyn PSOCipher + Send>>>,
|
||||
client_receiver: async_std::sync::Receiver<ServerStateAction<S>>)
|
||||
where
|
||||
S: SendServerPacket + std::fmt::Debug + Send + 'static,
|
||||
{
|
||||
async_std::task::spawn(async move {
|
||||
@ -264,26 +266,85 @@ async fn client_send_loop<S>(client_id: ClientId,
|
||||
});
|
||||
}
|
||||
|
||||
async fn state_client_loop<STATE, S, R, E>(state: Arc<Mutex<STATE>>,
|
||||
server_state_receiver: async_std::sync::Receiver<ClientAction<ServerStateAction<S>, R>>) where
|
||||
STATE: ServerState<SendPacket=S, RecvPacket=R, PacketError=E> + 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();
|
||||
|
||||
pub async fn mainloop_async<STATE, S, R, E>(state: STATE, port: u16) where
|
||||
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, S, R, E>(state: Arc<Mutex<STATE>>, client_port: u16) -> Pin<Box<dyn Future<Output = ()>>>
|
||||
where
|
||||
STATE: ServerState<SendPacket=S, RecvPacket=R, PacketError=E> + 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, S, R, E>(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
|
||||
}))
|
||||
}
|
||||
|
220
src/common/mainloop/interserver.rs
Normal file
220
src/common/mainloop/interserver.rs
Normal file
@ -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<R: DeserializeOwned + std::fmt::Debug + Send>(&mut self) -> Result<R, MessageReceiverError> {
|
||||
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<S, R> {
|
||||
NewConnection(ServerId, async_std::sync::Sender<S>),
|
||||
Message(ServerId, R),
|
||||
Disconnect(ServerId),
|
||||
}
|
||||
|
||||
async fn interserver_state_loop<A, S, R>(state: Arc<Mutex<A>>, action_receiver: async_std::sync::Receiver<InterserverInputAction<S, R>>)
|
||||
where
|
||||
A: InterserverActor<SendMessage=S, RecvMessage=R, Error=()> + 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<S, R>(server_id: ServerId,
|
||||
socket: async_std::net::TcpStream,
|
||||
state_loop_sender: async_std::sync::Sender<InterserverInputAction<S, R>>,
|
||||
output_loop_sender: async_std::sync::Sender<S>)
|
||||
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<S>(server_id: ServerId,
|
||||
mut socket: async_std::net::TcpStream,
|
||||
output_loop_receiver: async_std::sync::Receiver<S>)
|
||||
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<EG: EntityGateway + 'static>(state: Arc<Mutex<CharacterServerState<EG>>>, port: u16) -> Pin<Box<dyn Future<Output = ()>>> {
|
||||
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<EG: EntityGateway + 'static>(state: Arc<Mutex<ShipServerState<EG>>>, ip: std::net::Ipv4Addr, port: u16) -> Pin<Box<dyn Future<Output = ()>>> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
45
src/common/mainloop/mod.rs
Normal file
45
src/common/mainloop/mod.rs
Normal file
@ -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<Box<dyn Future<Output = ()>>> {
|
||||
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<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 client_mainloop = client_accept_mainloop(login_state.clone(), login_port);
|
||||
Box::pin(client_mainloop)
|
||||
}
|
||||
|
||||
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 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<EG: EntityGateway + 'static>(ship_state: ShipServerState<EG>, ship_port: u16, comm_ip: std::net::Ipv4Addr, comm_port: u16) -> Pin<Box<dyn Future<Output = ()>>> {
|
||||
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(|_| ()))
|
||||
}
|
@ -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]
|
||||
|
@ -17,6 +17,7 @@ pub trait SendServerPacket: Sized + Sync {
|
||||
fn as_bytes(&self) -> Vec<u8>;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
@ -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)]
|
||||
|
@ -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<EG: EntityGateway> {
|
||||
entity_gateway: EG,
|
||||
param_header: ParamDataHeader,
|
||||
param_data: Vec<u8>,
|
||||
clients: HashMap<ClientId, ClientState>,
|
||||
ships: Vec<Ship>,
|
||||
ships: BTreeMap<ServerId, Ship>,
|
||||
level_table: CharacterLevelTable,
|
||||
}
|
||||
|
||||
|
||||
async fn new_character<EG: EntityGateway>(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<EG: EntityGateway>(entity_gateway: &mut EG, user: &UserAc
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl<EG: EntityGateway> CharacterServerState<EG> {
|
||||
pub fn new(entity_gateway: EG) -> CharacterServerState<EG> {
|
||||
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<EG: EntityGateway> CharacterServerState<EG> {
|
||||
|
||||
fn send_ship_list(&mut self, _id: ClientId, _pkt: &Login) -> Result<Vec<SendCharacterPacket>, 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<EG: EntityGateway> CharacterServerState<EG> {
|
||||
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<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 {
|
||||
let mut character = NewCharacterEntity::new(user.id);
|
||||
|
@ -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<EG: EntityGateway> ServerState for LoginServerState<EG> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::time::SystemTime;
|
||||
|
@ -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<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_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<EG: EntityGateway> {
|
||||
entity_gateway: EG,
|
||||
@ -256,20 +310,13 @@ pub struct ShipServerState<EG: EntityGateway> {
|
||||
pub rooms: Rooms,
|
||||
item_manager: items::ItemManager,
|
||||
quests: quests::QuestList,
|
||||
ip: Ipv4Addr,
|
||||
port: u16,
|
||||
}
|
||||
|
||||
impl<EG: EntityGateway> ShipServerState<EG> {
|
||||
pub fn new(entity_gateway: EG) -> ShipServerState<EG> {
|
||||
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<EG> {
|
||||
ShipServerStateBuilder::new()
|
||||
}
|
||||
|
||||
async fn message(&mut self, id: ClientId, msg: &Message) -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> {
|
||||
@ -493,3 +540,28 @@ impl<EG: EntityGateway> ServerState for ShipServerState<EG> {
|
||||
}).collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<EG: EntityGateway> InterserverActor for ShipServerState<EG> {
|
||||
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<Vec<(ServerId, Self::SendMessage)>, Self::Error> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
|
||||
async fn on_disconnect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user