Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
f04ae8113f | |||
feb09cc13b | |||
fba46dd0d8 |
@ -1,5 +1,9 @@
|
|||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use log::{info};
|
use log::{info};
|
||||||
|
use async_std::channel;
|
||||||
|
|
||||||
|
use futures::stream::StreamExt;
|
||||||
|
use futures::future::join_all;
|
||||||
|
|
||||||
use elseware::common::interserver::AuthToken;
|
use elseware::common::interserver::AuthToken;
|
||||||
use elseware::login::login::LoginServerState;
|
use elseware::login::login::LoginServerState;
|
||||||
@ -56,7 +60,6 @@ fn main() {
|
|||||||
username: if i == 0 { "hi".to_string() } else { format!("hi{}", i+1) },
|
username: if i == 0 { "hi".to_string() } else { format!("hi{}", i+1) },
|
||||||
password: bcrypt::hash("qwer", 5).unwrap(),
|
password: bcrypt::hash("qwer", 5).unwrap(),
|
||||||
guildcard: i + 1,
|
guildcard: i + 1,
|
||||||
team_id: None,
|
|
||||||
banned_until: None,
|
banned_until: None,
|
||||||
muted_until: None,
|
muted_until: None,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
@ -338,20 +341,21 @@ fn main() {
|
|||||||
let (patch_file_tree, patch_file_lookup) = generate_patch_tree(patch_config.path.as_str());
|
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_state = PatchServerState::new(patch_file_tree, patch_file_lookup, patch_motd);
|
||||||
let patch_loop = async_std::task::spawn(async move {
|
let patch_loop = async_std::task::spawn(async move {
|
||||||
elseware::common::mainloop::run_server(patch_state, patch_config.port).await;
|
elseware::common::mainloop::run_server(patch_state, patch_config.port, None).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
info!("[auth] starting server");
|
info!("[auth] starting server");
|
||||||
let login_state = LoginServerState::new(entity_gateway.clone(), "127.0.0.1".parse().unwrap());
|
let login_state = LoginServerState::new(entity_gateway.clone(), "127.0.0.1".parse().unwrap());
|
||||||
let login_loop = async_std::task::spawn(async move {
|
let login_loop = async_std::task::spawn(async move {
|
||||||
elseware::common::mainloop::run_server(login_state, elseware::login::login::LOGIN_PORT).await;
|
elseware::common::mainloop::run_server(login_state, elseware::login::login::LOGIN_PORT, None).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
info!("[character] starting server");
|
info!("[character] starting server");
|
||||||
let char_state = CharacterServerState::new(entity_gateway.clone(), AuthToken("".into()));
|
let char_state = CharacterServerState::new(entity_gateway.clone(), AuthToken("".into()));
|
||||||
let sub_char_state = char_state.clone();
|
let sub_char_state = char_state.clone();
|
||||||
|
|
||||||
let character_loop = async_std::task::spawn(async move {
|
let character_loop = async_std::task::spawn(async move {
|
||||||
elseware::common::mainloop::run_server(sub_char_state, elseware::login::character::CHARACTER_PORT).await;
|
elseware::common::mainloop::run_server(sub_char_state, elseware::login::character::CHARACTER_PORT, None).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
let sub_char_state = char_state.clone();
|
let sub_char_state = char_state.clone();
|
||||||
@ -368,12 +372,13 @@ fn main() {
|
|||||||
.gateway(entity_gateway.clone())
|
.gateway(entity_gateway.clone())
|
||||||
.build();
|
.build();
|
||||||
let sub_ship_state = ship_state.clone();
|
let sub_ship_state = ship_state.clone();
|
||||||
|
let (interserver_tx, interserver_rx) = channel::unbounded();
|
||||||
let ship_loop1 = async_std::task::spawn(async move {
|
let ship_loop1 = async_std::task::spawn(async move {
|
||||||
elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT).await;
|
elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT, Some(interserver_rx)).await;
|
||||||
});
|
});
|
||||||
let sub_ship_state = ship_state.clone();
|
let sub_ship_state = ship_state.clone();
|
||||||
let inter_ship_loop1 = async_std::task::spawn(async move {
|
let inter_ship_loop1 = async_std::task::spawn(async move {
|
||||||
elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT).await;
|
elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT, interserver_tx).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
let ship_state = ShipServerStateBuilder::default()
|
let ship_state = ShipServerStateBuilder::default()
|
||||||
@ -384,12 +389,13 @@ fn main() {
|
|||||||
.gateway(entity_gateway.clone())
|
.gateway(entity_gateway.clone())
|
||||||
.build();
|
.build();
|
||||||
let sub_ship_state = ship_state.clone();
|
let sub_ship_state = ship_state.clone();
|
||||||
|
let (interserver_tx, interserver_rx) = channel::unbounded();
|
||||||
let ship_loop2 = async_std::task::spawn(async move {
|
let ship_loop2 = async_std::task::spawn(async move {
|
||||||
elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT+2000).await;
|
elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT+2000, Some(interserver_rx)).await;
|
||||||
});
|
});
|
||||||
let sub_ship_state = ship_state.clone();
|
let sub_ship_state = ship_state.clone();
|
||||||
let inter_ship_loop2 = async_std::task::spawn(async move {
|
let inter_ship_loop2 = async_std::task::spawn(async move {
|
||||||
elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT).await;
|
elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT, interserver_tx).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
let ship_state = ShipServerStateBuilder::default()
|
let ship_state = ShipServerStateBuilder::default()
|
||||||
@ -399,12 +405,13 @@ fn main() {
|
|||||||
.gateway(entity_gateway.clone())
|
.gateway(entity_gateway.clone())
|
||||||
.build();
|
.build();
|
||||||
let sub_ship_state = ship_state.clone();
|
let sub_ship_state = ship_state.clone();
|
||||||
|
let (interserver_tx, interserver_rx) = channel::unbounded();
|
||||||
let ship_loop3 = async_std::task::spawn(async move {
|
let ship_loop3 = async_std::task::spawn(async move {
|
||||||
elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT+3000).await;
|
elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT+3000, Some(interserver_rx)).await;
|
||||||
});
|
});
|
||||||
let sub_ship_state = ship_state.clone();
|
let sub_ship_state = ship_state.clone();
|
||||||
let inter_ship_loop3 = async_std::task::spawn(async move {
|
let inter_ship_loop3 = async_std::task::spawn(async move {
|
||||||
elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT).await;
|
elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT, interserver_tx).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
futures::future::join_all(vec![patch_loop, login_loop, character_loop, inter_character_loop,
|
futures::future::join_all(vec![patch_loop, login_loop, character_loop, inter_character_loop,
|
||||||
|
@ -2,7 +2,9 @@ use std::net::Ipv4Addr;
|
|||||||
use async_std::channel;
|
use async_std::channel;
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
|
use crate::common::serverstate::{ClientId, SendServerPacket};
|
||||||
use crate::entity::account::UserAccountId;
|
use crate::entity::account::UserAccountId;
|
||||||
|
use crate::entity::team::TeamEntityId;
|
||||||
use crate::entity::character::CharacterEntityId;
|
use crate::entity::character::CharacterEntityId;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Copy, Clone, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
@ -29,6 +31,7 @@ pub enum LoginMessage {
|
|||||||
ships: Vec<Ship>,
|
ships: Vec<Ship>,
|
||||||
},
|
},
|
||||||
RequestUsers,
|
RequestUsers,
|
||||||
|
CreatedTeam(UserAccountId, TeamEntityId),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
@ -43,17 +46,25 @@ pub enum ShipMessage {
|
|||||||
RequestShipList,
|
RequestShipList,
|
||||||
AddUser(UserAccountId),
|
AddUser(UserAccountId),
|
||||||
RemoveUser(UserAccountId),
|
RemoveUser(UserAccountId),
|
||||||
|
CreateTeam(UserAccountId, String),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum InterserverMessage<S, C> {
|
||||||
|
Server(ServerId, S),
|
||||||
|
Client(ClientId, C),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
pub trait InterserverActor: Clone {
|
pub trait InterserverActor: Clone {
|
||||||
type SendMessage: Serialize;
|
type SendClientMessage: SendServerPacket;
|
||||||
type RecvMessage: DeserializeOwned;
|
type SendServerMessage: Serialize;
|
||||||
|
type RecvServerMessage: DeserializeOwned;
|
||||||
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::SendServerMessage)>;
|
||||||
async fn on_action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result<Vec<(ServerId, Self::SendMessage)>, Self::Error>;
|
//async fn on_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)>;
|
async fn on_action(&mut self, id: ServerId, msg: Self::RecvServerMessage) -> Result<Vec<InterserverMessage<Self::SendServerMessage, Self::SendClientMessage>>, Self::Error>;
|
||||||
async fn set_sender(&mut self, server_id: ServerId, tx: channel::Sender<Self::SendMessage>);
|
async fn on_disconnect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendServerMessage)>;
|
||||||
|
async fn set_sender(&mut self, server_id: ServerId, tx: channel::Sender<Self::SendServerMessage>);
|
||||||
}
|
}
|
||||||
|
@ -217,7 +217,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_server<STATE, S, R, C, E>(mut state: STATE, port: u16)
|
pub async fn run_server<STATE, S, R, C, E>(mut state: STATE, port: u16, interserver: Option<channel::Receiver<(ClientId, S)>>)
|
||||||
where
|
where
|
||||||
STATE: ServerState<SendPacket=S, RecvPacket=R, Cipher=C, PacketError=E> + Send + 'static,
|
STATE: ServerState<SendPacket=S, RecvPacket=R, Cipher=C, PacketError=E> + Send + 'static,
|
||||||
S: SendServerPacket + std::fmt::Debug + Send + 'static,
|
S: SendServerPacket + std::fmt::Debug + Send + 'static,
|
||||||
@ -228,7 +228,20 @@ where
|
|||||||
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;
|
||||||
|
|
||||||
let clients = Arc::new(RwLock::new(HashMap::new()));
|
let clients = Arc::new(RwLock::new(HashMap::<ClientId, channel::Sender<S>>::new()));
|
||||||
|
|
||||||
|
if let Some(interserver) = interserver {
|
||||||
|
let clients = clients.clone();
|
||||||
|
async_std::task::spawn(async move {
|
||||||
|
loop {
|
||||||
|
if let Ok((id, msg)) = interserver.recv().await {
|
||||||
|
if let Some(client) = clients.read().await.get(&id) {
|
||||||
|
client.send(msg).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let (mut socket, addr) = listener.accept().await.unwrap();
|
let (mut socket, addr) = listener.accept().await.unwrap();
|
||||||
|
@ -8,7 +8,8 @@ use std::collections::HashMap;
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
|
|
||||||
use crate::common::interserver::{ServerId, InterserverActor};
|
use crate::common::serverstate::ClientId;
|
||||||
|
use crate::common::interserver::{ServerId, InterserverActor, InterserverMessage};
|
||||||
|
|
||||||
use libpso::crypto::{PSOCipher, NullCipher, CipherError};
|
use libpso::crypto::{PSOCipher, NullCipher, CipherError};
|
||||||
use crate::common::serverstate::{ServerState, SendServerPacket, RecvServerPacket};
|
use crate::common::serverstate::{ServerState, SendServerPacket, RecvServerPacket};
|
||||||
@ -53,11 +54,18 @@ impl MessageReceiver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn interserver_recv_loop<STATE, S, R, E>(mut state: STATE, server_id: ServerId, socket: async_std::net::TcpStream, ships: Arc<RwLock<HashMap<ServerId, channel::Sender<S>>>>)
|
async fn interserver_recv_loop<STATE, S, R, C, E>(
|
||||||
|
mut state: STATE,
|
||||||
|
server_id: ServerId,
|
||||||
|
socket: async_std::net::TcpStream,
|
||||||
|
ships: Arc<RwLock<HashMap<ServerId, channel::Sender<S>>>>,
|
||||||
|
interserver_tx: Option<channel::Sender<(ClientId, C)>>,
|
||||||
|
)
|
||||||
where
|
where
|
||||||
STATE: InterserverActor<SendMessage=S, RecvMessage=R, Error=E> + Send,
|
STATE: InterserverActor<SendServerMessage=S, RecvServerMessage=R, SendClientMessage=C, Error=E> + Send,
|
||||||
S: serde::Serialize + Debug + Send,
|
S: serde::Serialize + Debug + Send,
|
||||||
R: serde::de::DeserializeOwned + Debug + Send,
|
R: serde::de::DeserializeOwned + Debug + Send,
|
||||||
|
C: Debug + Send,
|
||||||
E: Debug + Send,
|
E: Debug + Send,
|
||||||
{
|
{
|
||||||
let mut msg_receiver = MessageReceiver::new(socket);
|
let mut msg_receiver = MessageReceiver::new(socket);
|
||||||
@ -69,14 +77,23 @@ where
|
|||||||
match state.on_action(server_id, msg).await {
|
match state.on_action(server_id, msg).await {
|
||||||
Ok(response) => {
|
Ok(response) => {
|
||||||
for resp in response {
|
for resp in response {
|
||||||
ships
|
match resp {
|
||||||
.read()
|
InterserverMessage::Server(id, msg) => {
|
||||||
.await
|
ships
|
||||||
.get(&resp.0)
|
.read()
|
||||||
.unwrap()
|
.await
|
||||||
.send(resp.1)
|
.get(&id)
|
||||||
.await
|
.unwrap()
|
||||||
.unwrap();
|
.send(msg)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
},
|
||||||
|
InterserverMessage::Client(id, msg) => {
|
||||||
|
if let Some(interserver_tx) = &interserver_tx {
|
||||||
|
interserver_tx.send((id, msg)).await.unwrap();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@ -133,11 +150,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_interserver_listen<STATE, S, R, E>(mut state: STATE, port: u16)
|
pub async fn run_interserver_listen<STATE, S, R, C, E>(mut state: STATE, port: u16)
|
||||||
where
|
where
|
||||||
STATE: InterserverActor<SendMessage=S, RecvMessage=R, Error=E> + Send + 'static,
|
STATE: InterserverActor<SendServerMessage=S, RecvServerMessage=R, SendClientMessage=C, Error=E> + Send + 'static,
|
||||||
S: serde::Serialize + Debug + Send + 'static,
|
S: serde::Serialize + Debug + Send + 'static,
|
||||||
R: serde::de::DeserializeOwned + Debug + Send,
|
R: serde::de::DeserializeOwned + Debug + Send,
|
||||||
|
C: Debug + Send,
|
||||||
E: Debug + Send,
|
E: Debug + Send,
|
||||||
{
|
{
|
||||||
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();
|
||||||
@ -168,7 +186,7 @@ where
|
|||||||
let rsocket = socket.clone();
|
let rsocket = socket.clone();
|
||||||
let rships = ships.clone();
|
let rships = ships.clone();
|
||||||
async_std::task::spawn(async move {
|
async_std::task::spawn(async move {
|
||||||
interserver_recv_loop(rstate, server_id, rsocket, rships).await;
|
interserver_recv_loop(rstate, server_id, rsocket, rships, None).await;
|
||||||
});
|
});
|
||||||
async_std::task::spawn(async move {
|
async_std::task::spawn(async move {
|
||||||
interserver_send_loop(server_id, socket, client_rx).await;
|
interserver_send_loop(server_id, socket, client_rx).await;
|
||||||
@ -176,11 +194,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_interserver_connect<STATE, S, R, E>(mut state: STATE, ip: std::net::Ipv4Addr, port: u16)
|
pub async fn run_interserver_connect<STATE, S, R, C, E>(mut state: STATE, ip: std::net::Ipv4Addr, port: u16, interserver_tx: channel::Sender<(ClientId, C)>)
|
||||||
where
|
where
|
||||||
STATE: InterserverActor<SendMessage=S, RecvMessage=R, Error=E> + Send + 'static,
|
STATE: InterserverActor<SendServerMessage=S, RecvServerMessage=R, SendClientMessage=C, Error=E> + Send + 'static,
|
||||||
S: serde::Serialize + Debug + Send + 'static,
|
S: serde::Serialize + Debug + Send + 'static,
|
||||||
R: serde::de::DeserializeOwned + Debug + Send,
|
R: serde::de::DeserializeOwned + Debug + Send,
|
||||||
|
C: Debug + Send + 'static,
|
||||||
E: Debug + Send,
|
E: Debug + Send,
|
||||||
{
|
{
|
||||||
let mut id = 0;
|
let mut id = 0;
|
||||||
@ -209,8 +228,9 @@ where
|
|||||||
let other_server = vec![(server_id, client_tx.clone())].into_iter().collect();
|
let other_server = vec![(server_id, client_tx.clone())].into_iter().collect();
|
||||||
let rstate = state.clone();
|
let rstate = state.clone();
|
||||||
let rsocket = socket.clone();
|
let rsocket = socket.clone();
|
||||||
|
let interserver_tx = interserver_tx.clone();
|
||||||
async_std::task::spawn(async move {
|
async_std::task::spawn(async move {
|
||||||
interserver_recv_loop(rstate, server_id, rsocket, Arc::new(RwLock::new(other_server))).await;
|
interserver_recv_loop(rstate, server_id, rsocket, Arc::new(RwLock::new(other_server)), Some(interserver_tx)).await;
|
||||||
});
|
});
|
||||||
let ssocket = socket.clone();
|
let ssocket = socket.clone();
|
||||||
async_std::task::spawn(async move {
|
async_std::task::spawn(async move {
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use libpso::character::settings;
|
use libpso::character::settings;
|
||||||
use libpso::character::guildcard;
|
use libpso::character::guildcard;
|
||||||
|
use super::team::TeamEntityId;
|
||||||
|
|
||||||
|
const GUILDCARD_OFFSET: u32 = 2300000;
|
||||||
|
|
||||||
pub const USERFLAG_NEWCHAR: u32 = 0x00000001;
|
pub const USERFLAG_NEWCHAR: u32 = 0x00000001;
|
||||||
pub const USERFLAG_DRESSINGROOM: u32 = 0x00000002;
|
pub const USERFLAG_DRESSINGROOM: u32 = 0x00000002;
|
||||||
@ -18,12 +21,11 @@ pub struct NewUserAccountEntity {
|
|||||||
pub email: String,
|
pub email: String,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub password: String,
|
pub password: String,
|
||||||
pub guildcard: u32,
|
pub guildcard: u32, // TODO: remove this, guildcard is based on account id
|
||||||
pub team_id: Option<u32>,
|
|
||||||
pub banned_until: Option<chrono::DateTime<chrono::Utc>>,
|
pub banned_until: Option<chrono::DateTime<chrono::Utc>>,
|
||||||
pub muted_until: Option<chrono::DateTime<chrono::Utc>>,
|
pub muted_until: Option<chrono::DateTime<chrono::Utc>>,
|
||||||
pub flags: u32,
|
pub flags: u32,
|
||||||
pub activated: bool
|
pub activated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for NewUserAccountEntity {
|
impl Default for NewUserAccountEntity {
|
||||||
@ -33,7 +35,6 @@ impl Default for NewUserAccountEntity {
|
|||||||
username: "".into(),
|
username: "".into(),
|
||||||
password: "".into(),
|
password: "".into(),
|
||||||
guildcard: 0xFFFFFFFF,
|
guildcard: 0xFFFFFFFF,
|
||||||
team_id: None,
|
|
||||||
banned_until: None,
|
banned_until: None,
|
||||||
muted_until: None,
|
muted_until: None,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
@ -48,7 +49,7 @@ pub struct UserAccountEntity {
|
|||||||
pub username: String,
|
pub username: String,
|
||||||
pub password: String,
|
pub password: String,
|
||||||
pub guildcard: u32,
|
pub guildcard: u32,
|
||||||
pub team_id: Option<u32>,
|
pub team_id: Option<TeamEntityId>,
|
||||||
pub banned_until: Option<chrono::DateTime<chrono::Utc>>,
|
pub banned_until: Option<chrono::DateTime<chrono::Utc>>,
|
||||||
pub muted_until: Option<chrono::DateTime<chrono::Utc>>,
|
pub muted_until: Option<chrono::DateTime<chrono::Utc>>,
|
||||||
pub created_at: chrono::DateTime<chrono::Utc>,
|
pub created_at: chrono::DateTime<chrono::Utc>,
|
||||||
@ -83,6 +84,10 @@ impl UserAccountEntity {
|
|||||||
pub fn is_currently_online(&self) -> bool {
|
pub fn is_currently_online(&self) -> bool {
|
||||||
self.at_login | self.at_character | self.at_ship
|
self.at_login | self.at_character | self.at_ship
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn guildcard(&self) -> u32 {
|
||||||
|
self.id.0 + GUILDCARD_OFFSET
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ use futures::Future;
|
|||||||
use crate::entity::account::*;
|
use crate::entity::account::*;
|
||||||
use crate::entity::character::*;
|
use crate::entity::character::*;
|
||||||
use crate::entity::item::*;
|
use crate::entity::item::*;
|
||||||
|
use crate::entity::team::*;
|
||||||
|
|
||||||
|
|
||||||
// TODO: better granularity?
|
// TODO: better granularity?
|
||||||
@ -13,6 +14,7 @@ use crate::entity::item::*;
|
|||||||
#[error("")]
|
#[error("")]
|
||||||
pub enum GatewayError {
|
pub enum GatewayError {
|
||||||
Error,
|
Error,
|
||||||
|
NotFound,
|
||||||
PgError(#[from] sqlx::Error)
|
PgError(#[from] sqlx::Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +150,26 @@ pub trait EntityGateway: Send + Sync {
|
|||||||
async fn set_character_playtime(&mut self, _char_id: &CharacterEntityId, _playtime: u32) -> Result<(), GatewayError> {
|
async fn set_character_playtime(&mut self, _char_id: &CharacterEntityId, _playtime: u32) -> Result<(), GatewayError> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn create_team(&mut self, _team_entity: NewTeamEntity) -> Result<TeamEntity, GatewayError> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_team(&mut self, _team_entity: &TeamEntityId) -> Result<TeamEntity, GatewayError> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn add_user_to_team(&mut self, _user: &UserAccountId, _team: &TeamEntityId) -> Result<(), GatewayError> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn remove_user_from_team(&mut self, _user: &UserAccountId) -> Result<(), GatewayError> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn team_point_item(&mut self, _user: &UserAccountId, _team: &TeamEntityId) -> Result<(), GatewayError> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ use futures::Future;
|
|||||||
|
|
||||||
use crate::entity::account::*;
|
use crate::entity::account::*;
|
||||||
use crate::entity::character::*;
|
use crate::entity::character::*;
|
||||||
|
use crate::entity::team::*;
|
||||||
use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError};
|
use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError};
|
||||||
use crate::entity::item::*;
|
use crate::entity::item::*;
|
||||||
|
|
||||||
@ -223,6 +224,7 @@ pub struct InMemoryGateway {
|
|||||||
mag_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<mag::MagModifier>>>>,
|
mag_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<mag::MagModifier>>>>,
|
||||||
weapon_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<weapon::WeaponModifier>>>>,
|
weapon_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<weapon::WeaponModifier>>>>,
|
||||||
trades: Arc<Mutex<Vec<TradeEntity>>>,
|
trades: Arc<Mutex<Vec<TradeEntity>>>,
|
||||||
|
teams: Arc<Mutex<BTreeMap<TeamEntityId, TeamEntity>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for InMemoryGateway {
|
impl Default for InMemoryGateway {
|
||||||
@ -240,6 +242,7 @@ impl Default for InMemoryGateway {
|
|||||||
mag_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
|
mag_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
|
||||||
weapon_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
|
weapon_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
|
||||||
trades: Arc::new(Mutex::new(Vec::new())),
|
trades: Arc::new(Mutex::new(Vec::new())),
|
||||||
|
teams: Arc::new(Mutex::new(BTreeMap::new())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -323,6 +326,7 @@ impl EntityGateway for InMemoryGateway {
|
|||||||
let mag_modifiers = self.mag_modifiers.lock().await.clone();
|
let mag_modifiers = self.mag_modifiers.lock().await.clone();
|
||||||
let weapon_modifiers = self.weapon_modifiers.lock().await.clone();
|
let weapon_modifiers = self.weapon_modifiers.lock().await.clone();
|
||||||
let trades = self.trades.lock().await.clone();
|
let trades = self.trades.lock().await.clone();
|
||||||
|
let teams = self.teams.lock().await.clone();
|
||||||
|
|
||||||
let working_gateway = InMemoryGateway {
|
let working_gateway = InMemoryGateway {
|
||||||
users: Arc::new(Mutex::new(users)),
|
users: Arc::new(Mutex::new(users)),
|
||||||
@ -337,6 +341,7 @@ impl EntityGateway for InMemoryGateway {
|
|||||||
mag_modifiers: Arc::new(Mutex::new(mag_modifiers)),
|
mag_modifiers: Arc::new(Mutex::new(mag_modifiers)),
|
||||||
weapon_modifiers: Arc::new(Mutex::new(weapon_modifiers)),
|
weapon_modifiers: Arc::new(Mutex::new(weapon_modifiers)),
|
||||||
trades: Arc::new(Mutex::new(trades)),
|
trades: Arc::new(Mutex::new(trades)),
|
||||||
|
teams: Arc::new(Mutex::new(teams)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let transaction = InMemoryGatewayTransaction {
|
let transaction = InMemoryGatewayTransaction {
|
||||||
@ -361,7 +366,7 @@ impl EntityGateway for InMemoryGateway {
|
|||||||
username: user.username,
|
username: user.username,
|
||||||
password: user.password,
|
password: user.password,
|
||||||
guildcard: user.guildcard,
|
guildcard: user.guildcard,
|
||||||
team_id: user.team_id,
|
team_id: None,
|
||||||
banned_until: user.banned_until,
|
banned_until: user.banned_until,
|
||||||
muted_until: user.muted_until,
|
muted_until: user.muted_until,
|
||||||
created_at: chrono::Utc::now(),
|
created_at: chrono::Utc::now(),
|
||||||
@ -627,4 +632,63 @@ impl EntityGateway for InMemoryGateway {
|
|||||||
Err(GatewayError::Error)
|
Err(GatewayError::Error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn create_team(&mut self, team_entity: NewTeamEntity) -> Result<TeamEntity, GatewayError> {
|
||||||
|
let new_team = {
|
||||||
|
let mut teams = self.teams.lock().await;
|
||||||
|
let id = teams
|
||||||
|
.iter()
|
||||||
|
.fold(0, |sum, (i, _)| std::cmp::max(sum, i.0))
|
||||||
|
+ 1;
|
||||||
|
|
||||||
|
let new_team = TeamEntity {
|
||||||
|
id: TeamEntityId(id),
|
||||||
|
owner: team_entity.created_by,
|
||||||
|
name: team_entity.name,
|
||||||
|
flag: [0; 2048],
|
||||||
|
};
|
||||||
|
|
||||||
|
teams.insert(new_team.id, new_team.clone());
|
||||||
|
new_team
|
||||||
|
};
|
||||||
|
|
||||||
|
self.add_user_to_team(&team_entity.created_by, &new_team.id).await.unwrap();
|
||||||
|
Ok(new_team)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_team(&mut self, team_id: &TeamEntityId) -> Result<TeamEntity, GatewayError> {
|
||||||
|
let teams = self.teams.lock().await;
|
||||||
|
if let Some(team) = teams.get(team_id) {
|
||||||
|
Ok(team.clone())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Err(GatewayError::Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn add_user_to_team(&mut self, user_id: &UserAccountId, team: &TeamEntityId) -> Result<(), GatewayError> {
|
||||||
|
let mut users = self.users.lock().await;
|
||||||
|
if let Some(user) = users.get_mut(user_id) {
|
||||||
|
user.team_id = Some(*team);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Err(GatewayError::Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn remove_user_from_team(&mut self, user_id: &UserAccountId) -> Result<(), GatewayError> {
|
||||||
|
let mut users = self.users.lock().await;
|
||||||
|
if let Some(user) = users.get_mut(user_id) {
|
||||||
|
user.team_id = None;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Err(GatewayError::Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn team_point_item(&mut self, _user: &UserAccountId, _team: &TeamEntityId) -> Result<(), GatewayError> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,3 +2,4 @@ pub mod gateway;
|
|||||||
pub mod account;
|
pub mod account;
|
||||||
pub mod character;
|
pub mod character;
|
||||||
pub mod item;
|
pub mod item;
|
||||||
|
pub mod team;
|
||||||
|
@ -12,27 +12,27 @@ use libpso::packet::login::*;
|
|||||||
use libpso::packet::ship::{MenuDetail, SmallLeftDialog};
|
use libpso::packet::ship::{MenuDetail, SmallLeftDialog};
|
||||||
use libpso::{PacketParseError, PSOPacket};
|
use libpso::{PacketParseError, PSOPacket};
|
||||||
use libpso::crypto::bb::PSOBBCipher;
|
use libpso::crypto::bb::PSOBBCipher;
|
||||||
use crate::entity::item;
|
|
||||||
use libpso::character::character;
|
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::interserver::{ServerId, InterserverActor, LoginMessage, ShipMessage, Ship, AuthToken, InterserverMessage};
|
||||||
use crate::common::leveltable::LEVEL_TABLE;
|
use crate::common::leveltable::LEVEL_TABLE;
|
||||||
use libpso::{utf8_to_array, utf8_to_utf16_array};
|
use libpso::{utf8_to_array, utf8_to_utf16_array};
|
||||||
|
|
||||||
use crate::entity::gateway::{EntityGateway, GatewayError};
|
use crate::entity::gateway::{EntityGateway, GatewayError};
|
||||||
use crate::entity::account::{UserAccountId, UserAccountEntity, NewUserSettingsEntity, USERFLAG_NEWCHAR, USERFLAG_DRESSINGROOM};
|
use crate::entity::account::{UserAccountId, UserAccountEntity, NewUserSettingsEntity, USERFLAG_NEWCHAR, USERFLAG_DRESSINGROOM};
|
||||||
|
use crate::entity::item;
|
||||||
use crate::entity::item::{NewItemEntity, ItemDetail, ItemNote, InventoryItemEntity, InventoryEntity, BankEntity, BankName, EquippedEntity, Meseta};
|
use crate::entity::item::{NewItemEntity, ItemDetail, ItemNote, InventoryItemEntity, InventoryEntity, BankEntity, BankName, EquippedEntity, Meseta};
|
||||||
use crate::entity::item::weapon::Weapon;
|
use crate::entity::item::weapon::Weapon;
|
||||||
use crate::entity::item::armor::Armor;
|
use crate::entity::item::armor::Armor;
|
||||||
use crate::entity::item::tech::Technique;
|
use crate::entity::item::tech::Technique;
|
||||||
use crate::entity::item::tool::Tool;
|
use crate::entity::item::tool::Tool;
|
||||||
use crate::entity::item::mag::Mag;
|
use crate::entity::item::mag::Mag;
|
||||||
|
use crate::entity::team::{TeamEntityId, NewTeamEntity};
|
||||||
use crate::entity::character::{CharacterEntity, NewCharacterEntity, CharacterClass, TechLevel};
|
use crate::entity::character::{CharacterEntity, NewCharacterEntity, CharacterClass, TechLevel};
|
||||||
|
|
||||||
use crate::login::login::{get_login_status};
|
use crate::login::login::{get_login_status};
|
||||||
use crate::common::interserver::AuthToken;
|
|
||||||
|
|
||||||
pub const CHARACTER_PORT: u16 = 12001;
|
pub const CHARACTER_PORT: u16 = 12001;
|
||||||
pub const SHIP_MENU_ID: u32 = 1;
|
pub const SHIP_MENU_ID: u32 = 1;
|
||||||
@ -343,7 +343,7 @@ impl<EG: EntityGateway + Clone> CharacterServerState<EG> {
|
|||||||
|
|
||||||
let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::new());
|
let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::new());
|
||||||
response.guildcard = user.guildcard;
|
response.guildcard = user.guildcard;
|
||||||
response.team_id = user.team_id.map_or(0, |ti| ti);
|
response.team_id = user.team_id.map_or(0, |ti| ti.0);
|
||||||
|
|
||||||
let mut client = self.clients.write().await;
|
let mut client = self.clients.write().await;
|
||||||
let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?;
|
let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?;
|
||||||
@ -427,7 +427,7 @@ impl<EG: EntityGateway + Clone> CharacterServerState<EG> {
|
|||||||
client.session.action = SessionAction::SelectCharacter;
|
client.session.action = SessionAction::SelectCharacter;
|
||||||
client.session.character_slot = select.slot as u8;
|
client.session.character_slot = select.slot as u8;
|
||||||
Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_char_select(user.guildcard,
|
Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_char_select(user.guildcard,
|
||||||
user.team_id.unwrap_or(1),
|
user.team_id.unwrap_or(TeamEntityId(1)).0, // TODO: why is this 1?
|
||||||
client.session)),
|
client.session)),
|
||||||
SendCharacterPacket::CharAck(CharAck {
|
SendCharacterPacket::CharAck(CharAck {
|
||||||
slot: select.slot,
|
slot: select.slot,
|
||||||
@ -520,7 +520,7 @@ impl<EG: EntityGateway + Clone> CharacterServerState<EG> {
|
|||||||
user.flags = 0;
|
user.flags = 0;
|
||||||
self.entity_gateway.save_user(user).await.unwrap();
|
self.entity_gateway.save_user(user).await.unwrap();
|
||||||
Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_char_select(user.guildcard,
|
Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_char_select(user.guildcard,
|
||||||
user.team_id.unwrap_or(1),
|
user.team_id.unwrap_or(TeamEntityId(1)).0, // TODO: why is this 1?
|
||||||
client.session)),
|
client.session)),
|
||||||
SendCharacterPacket::CharAck(CharAck {
|
SendCharacterPacket::CharAck(CharAck {
|
||||||
slot: preview.slot,
|
slot: preview.slot,
|
||||||
@ -648,15 +648,16 @@ impl<EG: EntityGateway + Clone> ServerState for CharacterServerState<EG> {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl<EG: EntityGateway + Clone> InterserverActor for CharacterServerState<EG> {
|
impl<EG: EntityGateway + Clone> InterserverActor for CharacterServerState<EG> {
|
||||||
type SendMessage = LoginMessage;
|
type SendClientMessage = SendCharacterPacket;
|
||||||
type RecvMessage = ShipMessage;
|
type SendServerMessage = LoginMessage;
|
||||||
|
type RecvServerMessage = ShipMessage;
|
||||||
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::SendServerMessage)> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result<Vec<(ServerId, Self::SendMessage)>, Self::Error> {
|
async fn on_action(&mut self, id: ServerId, msg: Self::RecvServerMessage) -> Result<Vec<InterserverMessage<Self::SendServerMessage, Self::SendClientMessage>>, Self::Error> {
|
||||||
dbg!(&id, &msg);
|
dbg!(&id, &msg);
|
||||||
match msg {
|
match msg {
|
||||||
ShipMessage::Authenticate(auth_token) => {
|
ShipMessage::Authenticate(auth_token) => {
|
||||||
@ -678,7 +679,7 @@ impl<EG: EntityGateway + Clone> InterserverActor for CharacterServerState<EG> {
|
|||||||
.await
|
.await
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(id, _)| {
|
.map(|(id, _)| {
|
||||||
(*id, LoginMessage::ShipList{ ships: ships.clone() })
|
InterserverMessage::Server(*id, LoginMessage::ShipList{ ships: ships.clone() })
|
||||||
})
|
})
|
||||||
.collect())
|
.collect())
|
||||||
},
|
},
|
||||||
@ -700,17 +701,20 @@ impl<EG: EntityGateway + Clone> InterserverActor for CharacterServerState<EG> {
|
|||||||
ShipMessage::RequestShipList => {
|
ShipMessage::RequestShipList => {
|
||||||
dbg!("request ship list", &self.authenticated_ships);
|
dbg!("request ship list", &self.authenticated_ships);
|
||||||
if self.authenticated_ships.read().await.contains(&id) {
|
if self.authenticated_ships.read().await.contains(&id) {
|
||||||
Ok(vec![(id, LoginMessage::ShipList {
|
Ok(vec![
|
||||||
ships: self.ships
|
InterserverMessage::Server(
|
||||||
.read()
|
id,
|
||||||
.await
|
LoginMessage::ShipList {
|
||||||
.iter()
|
ships: self.ships
|
||||||
.map(|(_, ship)| {
|
.read()
|
||||||
ship
|
.await
|
||||||
})
|
.iter()
|
||||||
.cloned()
|
.map(|(_, ship)| {
|
||||||
.collect()
|
ship
|
||||||
})])
|
})
|
||||||
|
.cloned()
|
||||||
|
.collect()
|
||||||
|
})])
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Ok(Vec::new())
|
Ok(Vec::new())
|
||||||
@ -719,10 +723,19 @@ impl<EG: EntityGateway + Clone> InterserverActor for CharacterServerState<EG> {
|
|||||||
ShipMessage::SendMail{..} => {
|
ShipMessage::SendMail{..} => {
|
||||||
Ok(Vec::new())
|
Ok(Vec::new())
|
||||||
},
|
},
|
||||||
|
ShipMessage::CreateTeam(user_id, team_name) => {
|
||||||
|
let team = self.entity_gateway.create_team(NewTeamEntity {
|
||||||
|
created_by: user_id,
|
||||||
|
name: team_name.clone(),
|
||||||
|
}).await.unwrap(); // TODO: unwrap
|
||||||
|
self.entity_gateway.add_user_to_team(&user_id, &team.id).await.unwrap(); // TODO: unwrap
|
||||||
|
|
||||||
|
Ok(vec![InterserverMessage::Server(id, LoginMessage::CreatedTeam(user_id, team.id))])
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_disconnect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> {
|
async fn on_disconnect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendServerMessage)> {
|
||||||
self.ships.write().await.remove(&id);
|
self.ships.write().await.remove(&id);
|
||||||
self.ship_sender.write().await.remove(&id);
|
self.ship_sender.write().await.remove(&id);
|
||||||
self.connected_clients
|
self.connected_clients
|
||||||
|
@ -2,6 +2,7 @@ use std::collections::HashMap;
|
|||||||
use async_std::sync::{Arc, RwLock, RwLockReadGuard};
|
use async_std::sync::{Arc, RwLock, RwLockReadGuard};
|
||||||
|
|
||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
|
use futures::stream::{FuturesOrdered, Stream, StreamExt};
|
||||||
|
|
||||||
use libpso::packet::ship::*;
|
use libpso::packet::ship::*;
|
||||||
use libpso::packet::login::Session;
|
use libpso::packet::login::Session;
|
||||||
@ -16,7 +17,6 @@ use crate::ship::items;
|
|||||||
use crate::ship::map::MapArea;
|
use crate::ship::map::MapArea;
|
||||||
use crate::ship::shops::{WeaponShopItem, ToolShopItem, ArmorShopItem};
|
use crate::ship::shops::{WeaponShopItem, ToolShopItem, ArmorShopItem};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct Clients(Arc<RwLock<HashMap<ClientId, RwLock<ClientState>>>>);
|
pub struct Clients(Arc<RwLock<HashMap<ClientId, RwLock<ClientState>>>>);
|
||||||
|
|
||||||
@ -101,6 +101,34 @@ impl Clients {
|
|||||||
|
|
||||||
Ok(func(&mut client).await)
|
Ok(func(&mut client).await)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn with_match<'a, P, F, T>(&'a self, pred: P, func: F) -> Result<T, ShipError>
|
||||||
|
where
|
||||||
|
P: Fn(&ClientState) -> bool,
|
||||||
|
F: for<'b> FnOnce(ClientId, &'b ClientState) -> BoxFuture<'b, T> + Send + 'a,
|
||||||
|
{
|
||||||
|
for (id, client) in self.0.read().await.iter() {
|
||||||
|
let client = client.read().await;
|
||||||
|
if pred(&*client) {
|
||||||
|
return Ok(func(*id, &*client).await)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(ShipError::ClientNotFound(ClientId(0xFFFFFFFF)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn with_match_mut<'a, P, F, T>(&'a self, pred: P, func: F) -> Result<T, ShipError>
|
||||||
|
where
|
||||||
|
P: Fn(&ClientState) -> bool,
|
||||||
|
F: for<'b> FnOnce(ClientId, &'b mut ClientState) -> BoxFuture<'b, T> + Send + 'a,
|
||||||
|
{
|
||||||
|
for (id, client) in self.0.read().await.iter() {
|
||||||
|
let mut client = client.write().await;
|
||||||
|
if pred(&*client) {
|
||||||
|
return Ok(func(*id, &mut *client).await)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(ShipError::ClientNotFound(ClientId(0xFFFFFFFF)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,3 +13,4 @@ pub mod packet;
|
|||||||
pub mod quests;
|
pub mod quests;
|
||||||
pub mod shops;
|
pub mod shops;
|
||||||
pub mod trade;
|
pub mod trade;
|
||||||
|
pub mod teams;
|
||||||
|
@ -3,6 +3,7 @@ pub mod message;
|
|||||||
pub mod room;
|
pub mod room;
|
||||||
pub mod quest;
|
pub mod quest;
|
||||||
pub mod ship;
|
pub mod ship;
|
||||||
|
pub mod team;
|
||||||
|
|
||||||
use libpso::character::character::Inventory;
|
use libpso::character::character::Inventory;
|
||||||
use libpso::packet::ship::{PlayerHeader, PlayerInfo};
|
use libpso::packet::ship::{PlayerHeader, PlayerInfo};
|
||||||
@ -15,7 +16,7 @@ use crate::ship::items::inventory::InventoryState;
|
|||||||
pub fn player_header(tag: u32, client: &ClientState, area_client: &AreaClient) -> PlayerHeader {
|
pub fn player_header(tag: u32, client: &ClientState, area_client: &AreaClient) -> PlayerHeader {
|
||||||
PlayerHeader {
|
PlayerHeader {
|
||||||
tag,
|
tag,
|
||||||
guildcard: client.user.id.0,
|
guildcard: client.user.guildcard(),
|
||||||
_unknown1: [0; 5],
|
_unknown1: [0; 5],
|
||||||
client_id: area_client.local_client.id() as u32,
|
client_id: area_client.local_client.id() as u32,
|
||||||
name: libpso::utf8_to_utf16_array!(client.character.name, 16),
|
name: libpso::utf8_to_utf16_array!(client.character.name, 16),
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use async_std::sync::{Arc, RwLock};
|
||||||
use libpso::packet::login::{Login, LoginResponse, AccountStatus, Session};
|
use libpso::packet::login::{Login, LoginResponse, AccountStatus, Session};
|
||||||
use libpso::packet::ship::*;
|
use libpso::packet::ship::*;
|
||||||
use crate::common::serverstate::ClientId;
|
use crate::common::serverstate::ClientId;
|
||||||
@ -13,7 +14,7 @@ pub async fn validate_login<EG>(id: ClientId,
|
|||||||
entity_gateway: &mut EG,
|
entity_gateway: &mut EG,
|
||||||
clients: &mut Clients,
|
clients: &mut Clients,
|
||||||
item_state: &mut ItemState,
|
item_state: &mut ItemState,
|
||||||
shipgate_sender: &Option<async_std::channel::Sender<ShipMessage>>,
|
shipgate_sender: &Arc<RwLock<Option<async_std::channel::Sender<ShipMessage>>>>,
|
||||||
ship_name: &str,
|
ship_name: &str,
|
||||||
num_blocks: usize)
|
num_blocks: usize)
|
||||||
-> Result<Vec<SendShipPacket>, ShipError>
|
-> Result<Vec<SendShipPacket>, ShipError>
|
||||||
@ -24,7 +25,7 @@ where
|
|||||||
Ok(user) => {
|
Ok(user) => {
|
||||||
let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::new());
|
let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::new());
|
||||||
response.guildcard = user.id.0;
|
response.guildcard = user.id.0;
|
||||||
response.team_id = user.team_id.map_or(31, |ti| ti);
|
response.team_id = user.team_id.map_or(31, |ti| ti.0); // TODO: why is this 31?
|
||||||
let characters = entity_gateway.get_characters_by_user(&user).await?;
|
let characters = entity_gateway.get_characters_by_user(&user).await?;
|
||||||
let character = characters
|
let character = characters
|
||||||
.get(pkt.session.character_slot as usize)
|
.get(pkt.session.character_slot as usize)
|
||||||
@ -36,7 +37,7 @@ where
|
|||||||
|
|
||||||
item_state.load_character(entity_gateway, &character).await?;
|
item_state.load_character(entity_gateway, &character).await?;
|
||||||
|
|
||||||
if let Some(shipgate_sender) = shipgate_sender.as_ref() {
|
if let Some(shipgate_sender) = shipgate_sender.read().await.as_ref() {
|
||||||
shipgate_sender.send(ShipMessage::AddUser(user.id)).await?;
|
shipgate_sender.send(ShipMessage::AddUser(user.id)).await?;
|
||||||
}
|
}
|
||||||
clients.add(id, ClientState::new(user, settings, character, pkt.session)).await;
|
clients.add(id, ClientState::new(user, settings, character, pkt.session)).await;
|
||||||
|
@ -12,7 +12,7 @@ pub async fn player_chat(id: ClientId,
|
|||||||
clients: &Clients)
|
clients: &Clients)
|
||||||
-> Result<Vec<(ClientId, SendShipPacket)>, ShipError> {
|
-> Result<Vec<(ClientId, SendShipPacket)>, ShipError> {
|
||||||
let cmsg = clients.with(id, |client| Box::pin(async move {
|
let cmsg = clients.with(id, |client| Box::pin(async move {
|
||||||
PlayerChat::new(client.user.id.0, msg.message)
|
PlayerChat::new(client.user.guildcard(), msg.message)
|
||||||
})).await?;
|
})).await?;
|
||||||
|
|
||||||
Ok(client_location.get_all_clients_by_client(id).await.unwrap().into_iter()
|
Ok(client_location.get_all_clients_by_client(id).await.unwrap().into_iter()
|
||||||
|
@ -60,7 +60,7 @@ pub async fn guildcard_send(id: ClientId,
|
|||||||
msg: GameMessage::GuildcardRecv(GuildcardRecv {
|
msg: GameMessage::GuildcardRecv(GuildcardRecv {
|
||||||
client: guildcard_send.client,
|
client: guildcard_send.client,
|
||||||
target: guildcard_send.target,
|
target: guildcard_send.target,
|
||||||
guildcard: client.user.id.0,
|
guildcard: client.user.guildcard(),
|
||||||
name: utf8_to_utf16_array!(client.character.name, 0x18),
|
name: utf8_to_utf16_array!(client.character.name, 0x18),
|
||||||
team: [0; 0x10], // TODO: teams not yet implemented
|
team: [0; 0x10], // TODO: teams not yet implemented
|
||||||
desc: utf8_to_utf16_array!(client.character.guildcard.description, 0x58),
|
desc: utf8_to_utf16_array!(client.character.guildcard.description, 0x58),
|
||||||
|
@ -7,4 +7,5 @@ pub mod room;
|
|||||||
pub mod settings;
|
pub mod settings;
|
||||||
pub mod quest;
|
pub mod quest;
|
||||||
pub mod ship;
|
pub mod ship;
|
||||||
|
pub mod teams;
|
||||||
pub mod trade;
|
pub mod trade;
|
||||||
|
@ -19,7 +19,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::interserver::{AuthToken, Ship, ServerId, InterserverActor, LoginMessage, ShipMessage};
|
use crate::common::interserver::{AuthToken, Ship, ServerId, InterserverActor, LoginMessage, ShipMessage, InterserverMessage};
|
||||||
|
|
||||||
use crate::login::character::SHIP_MENU_ID;
|
use crate::login::character::SHIP_MENU_ID;
|
||||||
|
|
||||||
@ -34,6 +34,7 @@ use crate::ship::map::{MapsError, MapAreaError};
|
|||||||
use crate::ship::packet::handler;
|
use crate::ship::packet::handler;
|
||||||
use crate::ship::shops::{WeaponShop, ToolShop, ArmorShop};
|
use crate::ship::shops::{WeaponShop, ToolShop, ArmorShop};
|
||||||
use crate::ship::trade::TradeState;
|
use crate::ship::trade::TradeState;
|
||||||
|
use crate::ship::teams::Teams;
|
||||||
|
|
||||||
// TODO: remove once stuff settles down
|
// TODO: remove once stuff settles down
|
||||||
pub use crate::ship::client::*;
|
pub use crate::ship::client::*;
|
||||||
@ -160,6 +161,8 @@ pub enum ShipError {
|
|||||||
RoomCreationError(#[from] room::RoomCreationError),
|
RoomCreationError(#[from] room::RoomCreationError),
|
||||||
#[error("channel send error {0}")]
|
#[error("channel send error {0}")]
|
||||||
SendError(#[from] async_std::channel::SendError<ShipMessage>),
|
SendError(#[from] async_std::channel::SendError<ShipMessage>),
|
||||||
|
#[error("team {0}")]
|
||||||
|
TeamError(#[from] crate::ship::teams::TeamError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Into<ClientLocationError>> From<I> for ShipError {
|
impl<I: Into<ClientLocationError>> From<I> for ShipError {
|
||||||
@ -204,6 +207,7 @@ pub enum RecvShipPacket {
|
|||||||
KeyboardConfig(KeyboardConfig),
|
KeyboardConfig(KeyboardConfig),
|
||||||
GamepadConfig(GamepadConfig),
|
GamepadConfig(GamepadConfig),
|
||||||
UpdateConfig(UpdateConfig),
|
UpdateConfig(UpdateConfig),
|
||||||
|
CreateTeam(CreateTeam),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RecvServerPacket for RecvShipPacket {
|
impl RecvServerPacket for RecvShipPacket {
|
||||||
@ -247,6 +251,7 @@ impl RecvServerPacket for RecvShipPacket {
|
|||||||
0x4ED => Ok(RecvShipPacket::KeyboardConfig(KeyboardConfig::from_bytes(data)?)),
|
0x4ED => Ok(RecvShipPacket::KeyboardConfig(KeyboardConfig::from_bytes(data)?)),
|
||||||
0x5ED => Ok(RecvShipPacket::GamepadConfig(GamepadConfig::from_bytes(data)?)),
|
0x5ED => Ok(RecvShipPacket::GamepadConfig(GamepadConfig::from_bytes(data)?)),
|
||||||
0x7ED => Ok(RecvShipPacket::UpdateConfig(UpdateConfig::from_bytes(data)?)),
|
0x7ED => Ok(RecvShipPacket::UpdateConfig(UpdateConfig::from_bytes(data)?)),
|
||||||
|
0x1EA => Ok(RecvShipPacket::CreateTeam(CreateTeam::from_bytes(data)?)),
|
||||||
_ => Err(PacketParseError::WrongPacketForServerType(u16::from_le_bytes([data[2], data[3]]), data.to_vec()))
|
_ => Err(PacketParseError::WrongPacketForServerType(u16::from_le_bytes([data[2], data[3]]), data.to_vec()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -267,6 +272,7 @@ pub enum SendShipPacket {
|
|||||||
PlayerChat(PlayerChat),
|
PlayerChat(PlayerChat),
|
||||||
SmallDialog(SmallDialog),
|
SmallDialog(SmallDialog),
|
||||||
SmallLeftDialog(SmallLeftDialog),
|
SmallLeftDialog(SmallLeftDialog),
|
||||||
|
LargeDialog(LargeDialog),
|
||||||
JoinRoom(JoinRoom),
|
JoinRoom(JoinRoom),
|
||||||
AddToRoom(AddToRoom),
|
AddToRoom(AddToRoom),
|
||||||
LeaveLobby(LeaveLobby),
|
LeaveLobby(LeaveLobby),
|
||||||
@ -292,6 +298,10 @@ pub enum SendShipPacket {
|
|||||||
CancelTrade(CancelTrade),
|
CancelTrade(CancelTrade),
|
||||||
TradeSuccessful(TradeSuccessful),
|
TradeSuccessful(TradeSuccessful),
|
||||||
LobbyEvent(LobbyEvent),
|
LobbyEvent(LobbyEvent),
|
||||||
|
//TeamActionResponse(TeamActionResponse),
|
||||||
|
CreateTeamResponse(CreateTeamResponse),
|
||||||
|
ClientTeamStateChanged(ClientTeamStateChanged),
|
||||||
|
TeamInfo(Box<TeamInfo>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SendServerPacket for SendShipPacket {
|
impl SendServerPacket for SendShipPacket {
|
||||||
@ -310,6 +320,7 @@ impl SendServerPacket for SendShipPacket {
|
|||||||
SendShipPacket::PlayerChat(pkt) => pkt.as_bytes(),
|
SendShipPacket::PlayerChat(pkt) => pkt.as_bytes(),
|
||||||
SendShipPacket::SmallDialog(pkt) => pkt.as_bytes(),
|
SendShipPacket::SmallDialog(pkt) => pkt.as_bytes(),
|
||||||
SendShipPacket::SmallLeftDialog(pkt) => pkt.as_bytes(),
|
SendShipPacket::SmallLeftDialog(pkt) => pkt.as_bytes(),
|
||||||
|
SendShipPacket::LargeDialog(pkt) => pkt.as_bytes(),
|
||||||
SendShipPacket::JoinRoom(pkt) => pkt.as_bytes(),
|
SendShipPacket::JoinRoom(pkt) => pkt.as_bytes(),
|
||||||
SendShipPacket::AddToRoom(pkt) => pkt.as_bytes(),
|
SendShipPacket::AddToRoom(pkt) => pkt.as_bytes(),
|
||||||
SendShipPacket::LeaveLobby(pkt) => pkt.as_bytes(),
|
SendShipPacket::LeaveLobby(pkt) => pkt.as_bytes(),
|
||||||
@ -335,6 +346,9 @@ impl SendServerPacket for SendShipPacket {
|
|||||||
SendShipPacket::CancelTrade(pkt) => pkt.as_bytes(),
|
SendShipPacket::CancelTrade(pkt) => pkt.as_bytes(),
|
||||||
SendShipPacket::TradeSuccessful(pkt) => pkt.as_bytes(),
|
SendShipPacket::TradeSuccessful(pkt) => pkt.as_bytes(),
|
||||||
SendShipPacket::LobbyEvent(pkt) => pkt.as_bytes(),
|
SendShipPacket::LobbyEvent(pkt) => pkt.as_bytes(),
|
||||||
|
SendShipPacket::CreateTeamResponse(pkt) => pkt.as_bytes(),
|
||||||
|
SendShipPacket::ClientTeamStateChanged(pkt) => pkt.as_bytes(),
|
||||||
|
SendShipPacket::TeamInfo(pkt) => pkt.as_bytes(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -437,9 +451,11 @@ impl<EG: EntityGateway + Clone + 'static> ShipServerStateBuilder<EG> {
|
|||||||
|
|
||||||
pub fn build(self) -> ShipServerState<EG> {
|
pub fn build(self) -> ShipServerState<EG> {
|
||||||
let blocks = std::iter::repeat_with(Block::default).take(self.num_blocks).collect(); // Block doesn't have a Clone impl which limits the easy ways to init this
|
let blocks = std::iter::repeat_with(Block::default).take(self.num_blocks).collect(); // Block doesn't have a Clone impl which limits the easy ways to init this
|
||||||
|
let entity_gateway = self.entity_gateway.unwrap();
|
||||||
|
let clients = Clients::default();
|
||||||
ShipServerState {
|
ShipServerState {
|
||||||
entity_gateway: self.entity_gateway.unwrap(),
|
entity_gateway: entity_gateway.clone(),
|
||||||
clients: Clients::default(),
|
clients: clients.clone(),
|
||||||
name: self.name.unwrap_or_else(|| "NAMENOTSET".into()),
|
name: self.name.unwrap_or_else(|| "NAMENOTSET".into()),
|
||||||
item_state: items::state::ItemState::default(),
|
item_state: items::state::ItemState::default(),
|
||||||
ip: self.ip.unwrap_or_else(|| Ipv4Addr::new(127,0,0,1)),
|
ip: self.ip.unwrap_or_else(|| Ipv4Addr::new(127,0,0,1)),
|
||||||
@ -447,10 +463,11 @@ impl<EG: EntityGateway + Clone + 'static> ShipServerStateBuilder<EG> {
|
|||||||
shops: ItemShops::default(),
|
shops: ItemShops::default(),
|
||||||
blocks: Blocks(blocks),
|
blocks: Blocks(blocks),
|
||||||
event: self.event.unwrap_or(ShipEvent::None),
|
event: self.event.unwrap_or(ShipEvent::None),
|
||||||
|
teams: Teams::new(entity_gateway, clients),
|
||||||
|
|
||||||
auth_token: self.auth_token.unwrap_or_else(|| AuthToken("".into())),
|
auth_token: self.auth_token.unwrap_or_else(|| AuthToken("".into())),
|
||||||
ship_list: Arc::new(RwLock::new(Vec::new())),
|
ship_list: Arc::new(RwLock::new(Vec::new())),
|
||||||
shipgate_sender: None,
|
shipgate_sender: Arc::new(RwLock::new(None)),
|
||||||
trades: Default::default(),
|
trades: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -487,13 +504,14 @@ pub struct ShipServerState<EG: EntityGateway + Clone + 'static> {
|
|||||||
shops: ItemShops,
|
shops: ItemShops,
|
||||||
pub blocks: Blocks,
|
pub blocks: Blocks,
|
||||||
event: ShipEvent,
|
event: ShipEvent,
|
||||||
|
teams: Teams<EG>,
|
||||||
|
|
||||||
ip: Ipv4Addr,
|
ip: Ipv4Addr,
|
||||||
port: u16,
|
port: u16,
|
||||||
|
|
||||||
auth_token: AuthToken,
|
auth_token: AuthToken,
|
||||||
ship_list: Arc<RwLock<Vec<Ship>>>,
|
ship_list: Arc<RwLock<Vec<Ship>>>,
|
||||||
shipgate_sender: Option<channel::Sender<ShipMessage>>,
|
shipgate_sender: Arc<RwLock<Option<channel::Sender<ShipMessage>>>>,
|
||||||
trades: TradeState,
|
trades: TradeState,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -803,6 +821,9 @@ impl<EG: EntityGateway + Clone> ServerState for ShipServerState<EG> {
|
|||||||
RecvShipPacket::GamepadConfig(gamepad_config) => {
|
RecvShipPacket::GamepadConfig(gamepad_config) => {
|
||||||
handler::settings::gamepad_config(id, gamepad_config, &self.clients, &mut self.entity_gateway).await?
|
handler::settings::gamepad_config(id, gamepad_config, &self.clients, &mut self.entity_gateway).await?
|
||||||
},
|
},
|
||||||
|
RecvShipPacket::CreateTeam(create_team) => {
|
||||||
|
handler::teams::create_team(id, create_team, &mut self.entity_gateway, &self.clients, &mut self.shipgate_sender).await?
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -828,7 +849,7 @@ impl<EG: EntityGateway + Clone> ServerState for ShipServerState<EG> {
|
|||||||
if let Some(mut client) = self.clients.remove(&id).await {
|
if let Some(mut client) = self.clients.remove(&id).await {
|
||||||
client.user.at_ship = false;
|
client.user.at_ship = false;
|
||||||
self.entity_gateway.save_user(&client.user).await;
|
self.entity_gateway.save_user(&client.user).await;
|
||||||
if let Some(shipgate_sender) = self.shipgate_sender.as_ref() {
|
if let Some(shipgate_sender) = self.shipgate_sender.read().await.as_ref() {
|
||||||
shipgate_sender.send(ShipMessage::RemoveUser(client.user.id)).await;
|
shipgate_sender.send(ShipMessage::RemoveUser(client.user.id)).await;
|
||||||
}
|
}
|
||||||
self.item_state.remove_character_from_room(&client.character).await
|
self.item_state.remove_character_from_room(&client.character).await
|
||||||
@ -843,14 +864,15 @@ impl<EG: EntityGateway + Clone> ServerState for ShipServerState<EG> {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl<EG: EntityGateway + Clone> InterserverActor for ShipServerState<EG> {
|
impl<EG: EntityGateway + Clone> InterserverActor for ShipServerState<EG> {
|
||||||
type SendMessage = ShipMessage;
|
type SendClientMessage = SendShipPacket;
|
||||||
type RecvMessage = LoginMessage;
|
type SendServerMessage = ShipMessage;
|
||||||
type Error = ();
|
type RecvServerMessage = LoginMessage;
|
||||||
|
type Error = ShipError;
|
||||||
|
|
||||||
async fn on_connect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> {
|
async fn on_connect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendServerMessage)> {
|
||||||
vec![
|
vec![
|
||||||
(id, ShipMessage::Authenticate(self.auth_token.clone())),
|
(id, ShipMessage::Authenticate(self.auth_token.clone())),
|
||||||
(id, ShipMessage::NewShip(Ship {
|
(id, ShipMessage::NewShip(Ship {
|
||||||
name: self.name.clone(),
|
name: self.name.clone(),
|
||||||
ip: self.ip,
|
ip: self.ip,
|
||||||
port: self.port,
|
port: self.port,
|
||||||
@ -860,7 +882,7 @@ impl<EG: EntityGateway + Clone> InterserverActor for ShipServerState<EG> {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_action(&mut self, _id: ServerId, msg: Self::RecvMessage) -> Result<Vec<(ServerId, Self::SendMessage)>, Self::Error> {
|
async fn on_action(&mut self, _id: ServerId, msg: Self::RecvServerMessage) -> Result<Vec<InterserverMessage<Self::SendServerMessage, Self::SendClientMessage>>, Self::Error> {
|
||||||
match msg {
|
match msg {
|
||||||
LoginMessage::SendMail{..} => {
|
LoginMessage::SendMail{..} => {
|
||||||
Ok(Vec::new())
|
Ok(Vec::new())
|
||||||
@ -883,15 +905,51 @@ impl<EG: EntityGateway + Clone> InterserverActor for ShipServerState<EG> {
|
|||||||
*/
|
*/
|
||||||
// TODO
|
// TODO
|
||||||
Ok(Vec::new())
|
Ok(Vec::new())
|
||||||
}
|
},
|
||||||
|
LoginMessage::CreatedTeam(user_id, team_id) => {
|
||||||
|
let client_id = self.clients.with_match_mut(|c| c.user.id == user_id, |client_id, client| Box::pin(async move {
|
||||||
|
client.user.team_id = Some(team_id);
|
||||||
|
client_id
|
||||||
|
})).await?;
|
||||||
|
let team_pkts = self.clients.with(client_id, |client| {
|
||||||
|
let mut teams = self.teams.clone();
|
||||||
|
Box::pin(async move {
|
||||||
|
let team_pkts = teams.get_team(client_id).await
|
||||||
|
.and_then(|team| {
|
||||||
|
let team = team.ok_or_else(|| super::teams::TeamError::ClientHasNoTeam(client_id))?;
|
||||||
|
Ok((
|
||||||
|
crate::ship::packet::builder::team::team_info(client_id, client, &team),
|
||||||
|
crate::ship::packet::builder::team::client_team_state_changed(client_id, client, &team),
|
||||||
|
))
|
||||||
|
});
|
||||||
|
team_pkts
|
||||||
|
})
|
||||||
|
}).await?;
|
||||||
|
|
||||||
|
match team_pkts {
|
||||||
|
Ok((team_info, client_team_state_changed)) => {
|
||||||
|
Ok(vec![
|
||||||
|
InterserverMessage::Client(client_id, SendShipPacket::CreateTeamResponse(CreateTeamResponse::success())),
|
||||||
|
InterserverMessage::Client(client_id, SendShipPacket::TeamInfo(Box::new(team_info))), // TODO: send to neighbors
|
||||||
|
InterserverMessage::Client(client_id, SendShipPacket::ClientTeamStateChanged(client_team_state_changed)),
|
||||||
|
])
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
Ok(vec![
|
||||||
|
InterserverMessage::Client(client_id, SendShipPacket::CreateTeamResponse(CreateTeamResponse::failure())),
|
||||||
|
//InterserverMessage::Client(client_id, SendShipPacket::LargeDialog(LargeDialog::new(format!("failed to create team: {:?}", err)))),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_disconnect(&mut self, _id: ServerId) -> Vec<(ServerId, Self::SendMessage)> {
|
async fn on_disconnect(&mut self, _id: ServerId) -> Vec<(ServerId, Self::SendServerMessage)> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_sender(&mut self, _server_id: ServerId, sender: channel::Sender<Self::SendMessage>) {
|
async fn set_sender(&mut self, _server_id: ServerId, sender: channel::Sender<Self::SendServerMessage>) {
|
||||||
self.shipgate_sender = Some(sender);
|
*self.shipgate_sender.write().await = Some(sender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user