Merge pull request 'misc shit' (#246) from cleaning_up into master
This commit is contained in:
commit
898cb9064d
@ -34,4 +34,5 @@ refinery = { version = "0.3.0", features = ["postgres"] }
|
|||||||
sqlx = { version = "0.4.0-beta.1", features = ["postgres", "json", "chrono"] }
|
sqlx = { version = "0.4.0-beta.1", features = ["postgres", "json", "chrono"] }
|
||||||
strum = "0.19.5"
|
strum = "0.19.5"
|
||||||
strum_macros = "0.19"
|
strum_macros = "0.19"
|
||||||
|
anyhow = "1.0.33"
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ use elseware::entity::gateway::postgres::PostgresGateway;
|
|||||||
use elseware::login::login::LoginServerState;
|
use elseware::login::login::LoginServerState;
|
||||||
use elseware::login::character::CharacterServerState;
|
use elseware::login::character::CharacterServerState;
|
||||||
use elseware::common::mainloop::{login_mainloop, character_mainloop};
|
use elseware::common::mainloop::{login_mainloop, character_mainloop};
|
||||||
|
use elseware::common::interserver::AuthToken;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let colors = fern::colors::ColoredLevelConfig::new()
|
let colors = fern::colors::ColoredLevelConfig::new()
|
||||||
@ -33,13 +34,14 @@ fn main() {
|
|||||||
let db_password = std::env::var("DB_PASSWORD").unwrap();
|
let db_password = std::env::var("DB_PASSWORD").unwrap();
|
||||||
let db_dbname = std::env::var("DB_DBNAME").unwrap();
|
let db_dbname = std::env::var("DB_DBNAME").unwrap();
|
||||||
let charserv_ip = std::env::var("CHARSERV_IP").unwrap().parse().unwrap();
|
let charserv_ip = std::env::var("CHARSERV_IP").unwrap().parse().unwrap();
|
||||||
|
let shipgate_token = std::env::var("SHIPGATE_TOKEN").unwrap();
|
||||||
let entity_gateway = PostgresGateway::new(&db_host, &db_dbname, &db_username, &db_password);
|
let entity_gateway = PostgresGateway::new(&db_host, &db_dbname, &db_username, &db_password);
|
||||||
|
|
||||||
let thread_entity_gateway = entity_gateway.clone();
|
let thread_entity_gateway = entity_gateway.clone();
|
||||||
let login_state = LoginServerState::new(thread_entity_gateway, charserv_ip);
|
let login_state = LoginServerState::new(thread_entity_gateway, charserv_ip);
|
||||||
let login_loop = login_mainloop(login_state, elseware::login::login::LOGIN_PORT);
|
let login_loop = login_mainloop(login_state, elseware::login::login::LOGIN_PORT);
|
||||||
|
|
||||||
let char_state = CharacterServerState::new(entity_gateway);
|
let char_state = CharacterServerState::new(entity_gateway, AuthToken(shipgate_token.into()));
|
||||||
let character_loop = character_mainloop(char_state, elseware::login::character::CHARACTER_PORT, elseware::login::login::COMMUNICATION_PORT);
|
let character_loop = character_mainloop(char_state, elseware::login::character::CHARACTER_PORT, elseware::login::login::COMMUNICATION_PORT);
|
||||||
|
|
||||||
info!("[auth/character] starting server");
|
info!("[auth/character] starting server");
|
||||||
|
@ -9,6 +9,7 @@ use elseware::entity::account::{NewUserAccountEntity, NewUserSettingsEntity};
|
|||||||
use elseware::entity::gateway::{EntityGateway, InMemoryGateway, PostgresGateway};
|
use elseware::entity::gateway::{EntityGateway, InMemoryGateway, PostgresGateway};
|
||||||
use elseware::entity::character::NewCharacterEntity;
|
use elseware::entity::character::NewCharacterEntity;
|
||||||
use elseware::entity::item::{NewItemEntity, ItemDetail, ItemLocation};
|
use elseware::entity::item::{NewItemEntity, ItemDetail, ItemLocation};
|
||||||
|
use elseware::common::interserver::AuthToken;
|
||||||
|
|
||||||
use elseware::entity::item;
|
use elseware::entity::item;
|
||||||
use elseware::common::mainloop::*;
|
use elseware::common::mainloop::*;
|
||||||
@ -405,7 +406,7 @@ fn main() {
|
|||||||
|
|
||||||
let thread_entity_gateway = entity_gateway.clone();
|
let thread_entity_gateway = entity_gateway.clone();
|
||||||
info!("[character] starting server");
|
info!("[character] starting server");
|
||||||
let char_state = CharacterServerState::new(thread_entity_gateway);
|
let char_state = CharacterServerState::new(thread_entity_gateway, AuthToken("".into()));
|
||||||
let character_loop = character_mainloop(char_state, elseware::login::character::CHARACTER_PORT, elseware::login::login::COMMUNICATION_PORT);
|
let character_loop = character_mainloop(char_state, elseware::login::character::CHARACTER_PORT, elseware::login::login::COMMUNICATION_PORT);
|
||||||
|
|
||||||
let thread_entity_gateway = entity_gateway.clone();
|
let thread_entity_gateway = entity_gateway.clone();
|
||||||
|
@ -2,6 +2,7 @@ use log::{info};
|
|||||||
use elseware::entity::gateway::postgres::PostgresGateway;
|
use elseware::entity::gateway::postgres::PostgresGateway;
|
||||||
use elseware::ship::ship::ShipServerStateBuilder;
|
use elseware::ship::ship::ShipServerStateBuilder;
|
||||||
use elseware::common::mainloop::ship_mainloop;
|
use elseware::common::mainloop::ship_mainloop;
|
||||||
|
use elseware::common::interserver::AuthToken;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let colors = fern::colors::ColoredLevelConfig::new()
|
let colors = fern::colors::ColoredLevelConfig::new()
|
||||||
@ -33,6 +34,7 @@ fn main() {
|
|||||||
let db_dbname = std::env::var("DB_DBNAME").unwrap();
|
let db_dbname = std::env::var("DB_DBNAME").unwrap();
|
||||||
let entity_gateway = PostgresGateway::new(&db_host, &db_dbname, &db_username, &db_password);
|
let entity_gateway = PostgresGateway::new(&db_host, &db_dbname, &db_username, &db_password);
|
||||||
|
|
||||||
|
let shipgate_token = std::env::var("SHIPGATE_TOKEN").unwrap();
|
||||||
let ship_name = std::env::var("SHIP_NAME").unwrap().parse().unwrap();
|
let ship_name = std::env::var("SHIP_NAME").unwrap().parse().unwrap();
|
||||||
let ip = std::env::var("SELF_IP").unwrap().parse().unwrap();
|
let ip = std::env::var("SELF_IP").unwrap().parse().unwrap();
|
||||||
let ship_state = ShipServerStateBuilder::new()
|
let ship_state = ShipServerStateBuilder::new()
|
||||||
@ -40,6 +42,7 @@ fn main() {
|
|||||||
.ip(ip)
|
.ip(ip)
|
||||||
.port(elseware::ship::ship::SHIP_PORT)
|
.port(elseware::ship::ship::SHIP_PORT)
|
||||||
.gateway(entity_gateway)
|
.gateway(entity_gateway)
|
||||||
|
.auth_token(AuthToken(shipgate_token.into()))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let shipgate_ip = std::env::var("SHIPGATE_IP").unwrap().parse().unwrap();
|
let shipgate_ip = std::env::var("SHIPGATE_IP").unwrap().parse().unwrap();
|
||||||
|
@ -5,7 +5,7 @@ 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)]
|
||||||
pub struct ServerId(pub usize);
|
pub struct ServerId(pub usize);
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
pub struct AuthToken(pub String);
|
pub struct AuthToken(pub String);
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
@ -65,7 +65,7 @@ pub trait EntityGateway: Send + Sync + Clone {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn save_item(&mut self, _item: &ItemEntity) -> Result<(), GatewayError> {
|
async fn change_item(&mut self, _id: &ItemEntityId, _item: &ItemDetail) -> Result<(), GatewayError> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,9 +165,12 @@ impl EntityGateway for InMemoryGateway {
|
|||||||
Ok(new_item)
|
Ok(new_item)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn save_item(&mut self, item: &ItemEntity) -> Result<(), GatewayError> {
|
async fn change_item(&mut self, id: &ItemEntityId, item: &ItemDetail) -> Result<(), GatewayError> {
|
||||||
let mut items = self.items.lock().unwrap();
|
let mut items = self.items.lock().unwrap();
|
||||||
items.insert(item.id, item.clone());
|
if let Some((_, ref mut old_item)) = items.iter_mut().find(|(existing_id, _)| **existing_id == *id) {
|
||||||
|
old_item.item = item.clone();
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,6 +312,14 @@ impl EntityGateway for PostgresGateway {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn change_item(&mut self, id: &ItemEntityId, item: &ItemDetail) -> Result<(), GatewayError> {
|
||||||
|
sqlx::query("update item set item = $1 where id = $2")
|
||||||
|
.bind(sqlx::types::Json(PgItemDetail::from(item.clone())))
|
||||||
|
.bind(id.0)
|
||||||
|
.execute(&self.pool).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn change_item_location(&mut self, item_id: &ItemEntityId, item_location: ItemLocation) -> Result<(), GatewayError> {
|
async fn change_item_location(&mut self, item_id: &ItemEntityId, item_location: ItemLocation) -> Result<(), GatewayError> {
|
||||||
let mut tx = self.pool.begin().await?;
|
let mut tx = self.pool.begin().await?;
|
||||||
if let ItemLocation::Inventory{slot, ..} = &item_location {
|
if let ItemLocation::Inventory{slot, ..} = &item_location {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#![allow(dead_code, unused_assignments)]
|
#![allow(dead_code, unused_assignments)]
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
||||||
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use crc::{crc32, Hasher32};
|
use crc::{crc32, Hasher32};
|
||||||
@ -28,11 +28,13 @@ use crate::entity::item::mag::Mag;
|
|||||||
use crate::entity::character::{CharacterEntity, NewCharacterEntity, CharacterClass, TechLevel};
|
use crate::entity::character::{CharacterEntity, NewCharacterEntity, CharacterClass, TechLevel};
|
||||||
|
|
||||||
use crate::login::login::{get_login_status, check_if_already_online};
|
use crate::login::login::{get_login_status, check_if_already_online};
|
||||||
|
use crate::common::interserver::AuthToken;
|
||||||
|
|
||||||
pub const CHARACTER_PORT: u16 = 12001;
|
pub const CHARACTER_PORT: u16 = 12001;
|
||||||
const SHIP_MENU_ID: u32 = 1;
|
const SHIP_MENU_ID: u32 = 1;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
#[error("")]
|
||||||
pub enum CharacterError {
|
pub enum CharacterError {
|
||||||
InvalidMenuSelection(u32, u32),
|
InvalidMenuSelection(u32, u32),
|
||||||
ClientNotFound(ClientId),
|
ClientNotFound(ClientId),
|
||||||
@ -174,6 +176,8 @@ pub struct CharacterServerState<EG: EntityGateway> {
|
|||||||
clients: HashMap<ClientId, ClientState>,
|
clients: HashMap<ClientId, ClientState>,
|
||||||
ships: BTreeMap<ServerId, Ship>,
|
ships: BTreeMap<ServerId, Ship>,
|
||||||
level_table: CharacterLevelTable,
|
level_table: CharacterLevelTable,
|
||||||
|
auth_token: AuthToken,
|
||||||
|
authenticated_ships: BTreeSet<ServerId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -266,7 +270,7 @@ async fn new_character<EG: EntityGateway>(entity_gateway: &mut EG, user: &UserAc
|
|||||||
|
|
||||||
|
|
||||||
impl<EG: EntityGateway> CharacterServerState<EG> {
|
impl<EG: EntityGateway> CharacterServerState<EG> {
|
||||||
pub fn new(entity_gateway: EG) -> CharacterServerState<EG> {
|
pub fn new(entity_gateway: EG, auth_token: AuthToken) -> CharacterServerState<EG> {
|
||||||
let (param_header, param_data) = generate_param_data("data/param/");
|
let (param_header, param_data) = generate_param_data("data/param/");
|
||||||
|
|
||||||
CharacterServerState {
|
CharacterServerState {
|
||||||
@ -276,10 +280,12 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
|
|||||||
clients: HashMap::new(),
|
clients: HashMap::new(),
|
||||||
ships: BTreeMap::new(),
|
ships: BTreeMap::new(),
|
||||||
level_table: CharacterLevelTable::new(),
|
level_table: CharacterLevelTable::new(),
|
||||||
|
auth_token: auth_token,
|
||||||
|
authenticated_ships: BTreeSet::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn validate_login(&mut self, id: ClientId, pkt: &Login) -> Result<Vec<SendCharacterPacket>, CharacterError> {
|
async fn validate_login(&mut self, id: ClientId, pkt: &Login) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
|
||||||
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
||||||
Ok(match get_login_status(&self.entity_gateway, pkt).await.and_then(check_if_already_online) {
|
Ok(match get_login_status(&self.entity_gateway, pkt).await.and_then(check_if_already_online) {
|
||||||
Ok(mut user) => {
|
Ok(mut user) => {
|
||||||
@ -299,7 +305,7 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_ship_list(&mut self, _id: ClientId, _pkt: &Login) -> Result<Vec<SendCharacterPacket>, CharacterError> {
|
fn send_ship_list(&mut self, _id: ClientId, _pkt: &Login) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
|
||||||
Ok(vec![SendCharacterPacket::Timestamp(Timestamp::new(chrono::Utc::now())),
|
Ok(vec![SendCharacterPacket::Timestamp(Timestamp::new(chrono::Utc::now())),
|
||||||
SendCharacterPacket::ShipList(ShipList::new(self.ships.iter().map(|(i, s)| {
|
SendCharacterPacket::ShipList(ShipList::new(self.ships.iter().map(|(i, s)| {
|
||||||
ShipListEntry {
|
ShipListEntry {
|
||||||
@ -312,7 +318,7 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_settings(&mut self, id: ClientId) -> Result<Vec<SendCharacterPacket>, CharacterError> {
|
async fn get_settings(&mut self, id: ClientId) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
|
||||||
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
||||||
let user = client.user.as_ref().unwrap();
|
let user = client.user.as_ref().unwrap();
|
||||||
|
|
||||||
@ -331,7 +337,7 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
|
|||||||
Ok(vec![pkt])
|
Ok(vec![pkt])
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn char_select(&mut self, id: ClientId, select: &CharSelect) -> Result<Vec<SendCharacterPacket>, CharacterError> {
|
async fn char_select(&mut self, id: ClientId, select: &CharSelect) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
|
||||||
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
||||||
if client.characters.is_none() {
|
if client.characters.is_none() {
|
||||||
client.characters = Some(self.entity_gateway.get_characters_by_user(client.user.as_ref().unwrap()).await.map_err(|_| CharacterError::CouldNotLoadCharacters)?);
|
client.characters = Some(self.entity_gateway.get_characters_by_user(client.user.as_ref().unwrap()).await.map_err(|_| CharacterError::CouldNotLoadCharacters)?);
|
||||||
@ -377,7 +383,7 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
|
|||||||
})]
|
})]
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn guildcard_data_header(&mut self, id: ClientId) -> Result<Vec<SendCharacterPacket>, CharacterError> {
|
async fn guildcard_data_header(&mut self, id: ClientId) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
|
||||||
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
||||||
let guildcard_data = self.entity_gateway.get_guild_card_data_by_user(client.user.as_ref().unwrap()).await.map_err(|_| CharacterError::CouldNotLoadGuildcard)?;
|
let guildcard_data = self.entity_gateway.get_guild_card_data_by_user(client.user.as_ref().unwrap()).await.map_err(|_| CharacterError::CouldNotLoadGuildcard)?;
|
||||||
|
|
||||||
@ -389,7 +395,7 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
|
|||||||
Ok(vec![SendCharacterPacket::GuildcardDataHeader(GuildcardDataHeader::new(bytes.len(), crc.sum32()))])
|
Ok(vec![SendCharacterPacket::GuildcardDataHeader(GuildcardDataHeader::new(bytes.len(), crc.sum32()))])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn guildcard_data_chunk(&mut self, id: ClientId, chunk: u32, again: u32) -> Result<Vec<SendCharacterPacket>, CharacterError> {
|
fn guildcard_data_chunk(&mut self, id: ClientId, chunk: u32, again: u32) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
|
||||||
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
||||||
Ok(if again != 0 {
|
Ok(if again != 0 {
|
||||||
let start = chunk as usize * GUILD_CARD_CHUNK_SIZE;
|
let start = chunk as usize * GUILD_CARD_CHUNK_SIZE;
|
||||||
@ -405,7 +411,7 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_flag(&mut self, id: ClientId, setflag: &SetFlag) -> Result<std::option::IntoIter<SendCharacterPacket>, CharacterError> {
|
async fn set_flag(&mut self, id: ClientId, setflag: &SetFlag) -> Result<std::option::IntoIter<SendCharacterPacket>, anyhow::Error> {
|
||||||
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
||||||
let mut user = client.user.as_mut().unwrap();
|
let mut user = client.user.as_mut().unwrap();
|
||||||
user.flags = setflag.flags;
|
user.flags = setflag.flags;
|
||||||
@ -413,7 +419,7 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
|
|||||||
Ok(None.into_iter())
|
Ok(None.into_iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn param_data_chunk_request(&mut self, id: ClientId, _request: &ParamDataChunkRequest) -> Result<Vec<SendCharacterPacket>, CharacterError> {
|
fn param_data_chunk_request(&mut self, id: ClientId, _request: &ParamDataChunkRequest) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
|
||||||
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
||||||
let chunk = client.param_index;
|
let chunk = client.param_index;
|
||||||
client.param_index += 1;
|
client.param_index += 1;
|
||||||
@ -434,7 +440,7 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
|
|||||||
|
|
||||||
|
|
||||||
// TODO: move USERFLAGS over to SessionAction
|
// TODO: move USERFLAGS over to SessionAction
|
||||||
async fn character_preview(&mut self, id: ClientId, preview: &CharacterPreview) -> Result<Vec<SendCharacterPacket>, CharacterError> {
|
async fn character_preview(&mut self, id: ClientId, preview: &CharacterPreview) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
|
||||||
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
||||||
let mut user = client.user.as_mut().unwrap();
|
let mut user = client.user.as_mut().unwrap();
|
||||||
if user.flags == USERFLAG_NEWCHAR {
|
if user.flags == USERFLAG_NEWCHAR {
|
||||||
@ -458,9 +464,9 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_ship(&mut self, menuselect: &MenuSelect) -> Result<Vec<SendCharacterPacket>, CharacterError> {
|
fn select_ship(&mut self, menuselect: &MenuSelect) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
|
||||||
if menuselect.menu != SHIP_MENU_ID {
|
if menuselect.menu != SHIP_MENU_ID {
|
||||||
return Err(CharacterError::InvalidMenuSelection(menuselect.menu, menuselect.item));
|
Err(CharacterError::InvalidMenuSelection(menuselect.menu, menuselect.item))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ship = self.ships.get(&ServerId(menuselect.item as usize))
|
let ship = self.ships.get(&ServerId(menuselect.item as usize))
|
||||||
@ -473,9 +479,9 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
|
|||||||
impl<EG: EntityGateway> ServerState for CharacterServerState<EG> {
|
impl<EG: EntityGateway> ServerState for CharacterServerState<EG> {
|
||||||
type SendPacket = SendCharacterPacket;
|
type SendPacket = SendCharacterPacket;
|
||||||
type RecvPacket = RecvCharacterPacket;
|
type RecvPacket = RecvCharacterPacket;
|
||||||
type PacketError = CharacterError;
|
type PacketError = anyhow::Error;
|
||||||
|
|
||||||
async fn on_connect(&mut self, id: ClientId) -> Result<Vec<OnConnect<Self::SendPacket>>, CharacterError> {
|
async fn on_connect(&mut self, id: ClientId) -> Result<Vec<OnConnect<Self::SendPacket>>, anyhow::Error> {
|
||||||
self.clients.insert(id, ClientState::new());
|
self.clients.insert(id, ClientState::new());
|
||||||
|
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
@ -492,7 +498,7 @@ impl<EG: EntityGateway> ServerState for CharacterServerState<EG> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn handle(&mut self, id: ClientId, pkt: &RecvCharacterPacket)
|
async fn handle(&mut self, id: ClientId, pkt: &RecvCharacterPacket)
|
||||||
-> Result<Box<dyn Iterator<Item = (ClientId, SendCharacterPacket)> + Send>, CharacterError> {
|
-> Result<Box<dyn Iterator<Item = (ClientId, SendCharacterPacket)> + Send>, anyhow::Error> {
|
||||||
Ok(match pkt {
|
Ok(match pkt {
|
||||||
RecvCharacterPacket::Login(login) => {
|
RecvCharacterPacket::Login(login) => {
|
||||||
if login.session.action == SessionAction::SelectCharacter {
|
if login.session.action == SessionAction::SelectCharacter {
|
||||||
@ -535,7 +541,7 @@ impl<EG: EntityGateway> ServerState for CharacterServerState<EG> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_disconnect(&mut self, id: ClientId) -> Result<Vec<(ClientId, SendCharacterPacket)>, CharacterError> {
|
async fn on_disconnect(&mut self, id: ClientId) -> Result<Vec<(ClientId, SendCharacterPacket)>, anyhow::Error> {
|
||||||
if let Some(client) = self.clients.remove(&id) {
|
if let Some(client) = self.clients.remove(&id) {
|
||||||
if let Some(mut user) = client.user {
|
if let Some(mut user) = client.user {
|
||||||
user.at_character= false;
|
user.at_character= false;
|
||||||
@ -558,9 +564,15 @@ impl<EG: EntityGateway> InterserverActor for CharacterServerState<EG> {
|
|||||||
|
|
||||||
async fn action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result<Vec<(ServerId, Self::SendMessage)>, Self::Error> {
|
async fn action(&mut self, id: ServerId, msg: Self::RecvMessage) -> Result<Vec<(ServerId, Self::SendMessage)>, Self::Error> {
|
||||||
match msg {
|
match msg {
|
||||||
ShipMessage::Authenticate(_auth_token) => {},
|
ShipMessage::Authenticate(auth_token) => {
|
||||||
|
if self.auth_token == auth_token {
|
||||||
|
self.authenticated_ships.insert(id);
|
||||||
|
}
|
||||||
|
},
|
||||||
ShipMessage::NewShip(new_ship) => {
|
ShipMessage::NewShip(new_ship) => {
|
||||||
self.ships.insert(id, new_ship);
|
if self.authenticated_ships.contains(&id) {
|
||||||
|
self.ships.insert(id, new_ship);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -681,7 +693,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut server = CharacterServerState::new(TestData {});
|
let mut server = CharacterServerState::new(TestData {}, AuthToken("".into()));
|
||||||
let mut clientstate = ClientState::new();
|
let mut clientstate = ClientState::new();
|
||||||
clientstate.user = Some(UserAccountEntity {
|
clientstate.user = Some(UserAccountEntity {
|
||||||
id: UserAccountId(1),
|
id: UserAccountId(1),
|
||||||
@ -716,7 +728,7 @@ mod test {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct TestData;
|
struct TestData;
|
||||||
impl EntityGateway for TestData {}
|
impl EntityGateway for TestData {}
|
||||||
let mut server = CharacterServerState::new(TestData {});
|
let mut server = CharacterServerState::new(TestData {}, AuthToken("".into()));
|
||||||
let send = server.handle(ClientId(1), &RecvCharacterPacket::Checksum(Checksum {checksum: 1234,
|
let send = server.handle(ClientId(1), &RecvCharacterPacket::Checksum(Checksum {checksum: 1234,
|
||||||
padding: 0,
|
padding: 0,
|
||||||
})).await.unwrap().collect::<Vec<_>>();
|
})).await.unwrap().collect::<Vec<_>>();
|
||||||
@ -746,7 +758,7 @@ mod test {
|
|||||||
at_ship: false,
|
at_ship: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut server = CharacterServerState::new(test_data.clone());
|
let mut server = CharacterServerState::new(test_data.clone(), AuthToken("".into()));
|
||||||
server.clients.insert(ClientId(1), fake_user.clone());
|
server.clients.insert(ClientId(1), fake_user.clone());
|
||||||
let mut send = server.handle(ClientId(1), &RecvCharacterPacket::SetFlag(SetFlag {flags: 1})).await.unwrap().collect::<Vec<_>>();
|
let mut send = server.handle(ClientId(1), &RecvCharacterPacket::SetFlag(SetFlag {flags: 1})).await.unwrap().collect::<Vec<_>>();
|
||||||
assert!(test_data.get_user_by_id(UserAccountId(3)).await.unwrap().flags == 1);
|
assert!(test_data.get_user_by_id(UserAccountId(3)).await.unwrap().flags == 1);
|
||||||
|
@ -20,7 +20,8 @@ use crate::entity::account::{UserAccountEntity};
|
|||||||
pub const LOGIN_PORT: u16 = 12000;
|
pub const LOGIN_PORT: u16 = 12000;
|
||||||
pub const COMMUNICATION_PORT: u16 = 12123;
|
pub const COMMUNICATION_PORT: u16 = 12123;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
#[error("")]
|
||||||
pub enum LoginError {
|
pub enum LoginError {
|
||||||
DbError
|
DbError
|
||||||
}
|
}
|
||||||
@ -62,11 +63,7 @@ pub async fn get_login_status(entity_gateway: &impl EntityGateway, pkt: &Login)
|
|||||||
let username = array_to_utf8(pkt.username).map_err(|_err| AccountStatus::Error)?;
|
let username = array_to_utf8(pkt.username).map_err(|_err| AccountStatus::Error)?;
|
||||||
let password = array_to_utf8(pkt.password).map_err(|_err| AccountStatus::Error)?;
|
let password = array_to_utf8(pkt.password).map_err(|_err| AccountStatus::Error)?;
|
||||||
let user = entity_gateway.get_user_by_name(username).await.map_err(|_| AccountStatus::InvalidUser)?;
|
let user = entity_gateway.get_user_by_name(username).await.map_err(|_| AccountStatus::InvalidUser)?;
|
||||||
/*if user.is_currently_online() {
|
|
||||||
return Err(AccountStatus::AlreadyOnline)
|
|
||||||
}*/
|
|
||||||
|
|
||||||
log::info!("user: {}, activated {}", user.username, user.activated);
|
|
||||||
if !user.activated {
|
if !user.activated {
|
||||||
return Err(AccountStatus::PayUp)
|
return Err(AccountStatus::PayUp)
|
||||||
}
|
}
|
||||||
@ -110,7 +107,7 @@ impl<EG: EntityGateway> LoginServerState<EG> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn validate_login(&mut self, id: ClientId, pkt: &Login) -> Result<Vec<SendLoginPacket>, LoginError> {
|
async fn validate_login(&mut self, id: ClientId, pkt: &Login) -> Result<Vec<SendLoginPacket>, anyhow::Error> {
|
||||||
match get_login_status(&self.entity_gateway, pkt).await.and_then(check_if_already_online) {
|
match get_login_status(&self.entity_gateway, pkt).await.and_then(check_if_already_online) {
|
||||||
Ok(mut user) => {
|
Ok(mut user) => {
|
||||||
user.at_login = true;
|
user.at_login = true;
|
||||||
@ -133,9 +130,10 @@ impl<EG: EntityGateway> LoginServerState<EG> {
|
|||||||
impl<EG: EntityGateway> ServerState for LoginServerState<EG> {
|
impl<EG: EntityGateway> ServerState for LoginServerState<EG> {
|
||||||
type SendPacket = SendLoginPacket;
|
type SendPacket = SendLoginPacket;
|
||||||
type RecvPacket = RecvLoginPacket;
|
type RecvPacket = RecvLoginPacket;
|
||||||
type PacketError = LoginError;
|
//type PacketError = LoginError;
|
||||||
|
type PacketError = anyhow::Error;
|
||||||
|
|
||||||
async fn on_connect(&mut self, _id: ClientId) -> Result<Vec<OnConnect<Self::SendPacket>>, LoginError> {
|
async fn on_connect(&mut self, _id: ClientId) -> Result<Vec<OnConnect<Self::SendPacket>>, anyhow::Error> {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
let mut server_key = [0u8; 48];
|
let mut server_key = [0u8; 48];
|
||||||
@ -150,7 +148,7 @@ impl<EG: EntityGateway> ServerState for LoginServerState<EG> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn handle(&mut self, id: ClientId, pkt: &Self::RecvPacket)
|
async fn handle(&mut self, id: ClientId, pkt: &Self::RecvPacket)
|
||||||
-> Result<Box<dyn Iterator<Item = (ClientId, Self::SendPacket)> + Send>, LoginError> {
|
-> Result<Box<dyn Iterator<Item = (ClientId, Self::SendPacket)> + Send>, anyhow::Error> {
|
||||||
Ok(match pkt {
|
Ok(match pkt {
|
||||||
RecvLoginPacket::Login(login) => {
|
RecvLoginPacket::Login(login) => {
|
||||||
Box::new(self.validate_login(id, login).await?
|
Box::new(self.validate_login(id, login).await?
|
||||||
@ -162,7 +160,7 @@ impl<EG: EntityGateway> ServerState for LoginServerState<EG> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_disconnect(&mut self, id: ClientId) -> Result<Vec<(ClientId, SendLoginPacket)>, LoginError> {
|
async fn on_disconnect(&mut self, id: ClientId) -> Result<Vec<(ClientId, SendLoginPacket)>, anyhow::Error> {
|
||||||
if let Some(username) = self.clients.remove(&id) {
|
if let Some(username) = self.clients.remove(&id) {
|
||||||
if let Ok(mut user) = self.entity_gateway.get_user_by_name(username).await {
|
if let Ok(mut user) = self.entity_gateway.get_user_by_name(username).await {
|
||||||
user.at_login = false;
|
user.at_login = false;
|
||||||
@ -231,7 +229,7 @@ mod test {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn save_user(&mut self, user: &UserAccountEntity) -> Result<(), GatewayError> {
|
async fn save_user(&mut self, _user: &UserAccountEntity) -> Result<(), GatewayError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,112 +0,0 @@
|
|||||||
#![feature(const_generics)]
|
|
||||||
|
|
||||||
mod common;
|
|
||||||
mod login;
|
|
||||||
mod entity;
|
|
||||||
|
|
||||||
use std::thread;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use bcrypt;
|
|
||||||
|
|
||||||
use libpso::character::settings;
|
|
||||||
use libpso::character::character as pso_character;
|
|
||||||
use libpso::character::guildcard;
|
|
||||||
use libpso::{utf8_to_array, utf8_to_utf16_array};
|
|
||||||
|
|
||||||
use entity::gateway::EntityGateway;
|
|
||||||
use entity::account::{UserAccount, UserSettings, GuildCardData};
|
|
||||||
use entity::character::Character;
|
|
||||||
|
|
||||||
use login::login::LoginServerState;
|
|
||||||
use login::character::CharacterServerState;
|
|
||||||
|
|
||||||
use std::time::SystemTime;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct LoginStubData {
|
|
||||||
users: HashMap<String, UserAccount>,
|
|
||||||
characters: [Option<Character> ;4],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LoginStubData {
|
|
||||||
fn new() -> LoginStubData {
|
|
||||||
let mut c = pso_character::Character::default();
|
|
||||||
c.name = utf8_to_utf16_array!("Test Char", 16);
|
|
||||||
|
|
||||||
let mut users = HashMap::new();
|
|
||||||
users.insert("hi".to_string(), UserAccount {
|
|
||||||
id: 1,
|
|
||||||
username: "hi".to_owned(),
|
|
||||||
password: bcrypt::hash("qwer", 5).unwrap(),
|
|
||||||
guildcard: None,
|
|
||||||
team_id: None,
|
|
||||||
banned: false,
|
|
||||||
muted_until: SystemTime::now(),
|
|
||||||
created_at: SystemTime::now(),
|
|
||||||
flags: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
LoginStubData {
|
|
||||||
users: users,
|
|
||||||
|
|
||||||
characters: [Some(Character {
|
|
||||||
id: 1,
|
|
||||||
slot: 0,
|
|
||||||
user_id: 1,
|
|
||||||
character: c,
|
|
||||||
}),
|
|
||||||
None, None, None]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EntityGateway for LoginStubData {
|
|
||||||
fn get_user_by_name(&self, username: String) -> Option<UserAccount> {
|
|
||||||
self.users.get(&username).map(|user| user.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_user_settings_by_user(&self, user: &UserAccount) -> Option<UserSettings> {
|
|
||||||
Some(UserSettings {
|
|
||||||
id: 0,
|
|
||||||
user_id: user.id,
|
|
||||||
settings: settings::UserSettings::default()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_user(&mut self, user: &UserAccount) {
|
|
||||||
self.users.insert(user.username.clone(), user.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_characters_by_user(&self, _user: &UserAccount) -> [Option<Character>; 4] {
|
|
||||||
self.characters
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_character(&mut self, char: &Character) {
|
|
||||||
self.characters[char.slot as usize] = Some(char.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_guild_card_data_by_user(&self, user: &UserAccount) -> GuildCardData {
|
|
||||||
GuildCardData {
|
|
||||||
id: 1,
|
|
||||||
user_id: user.id,
|
|
||||||
guildcard: guildcard::GuildCardData::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
println!("[login+character] starting server");
|
|
||||||
|
|
||||||
let auth_thread = thread::spawn(|| {
|
|
||||||
let auth_state = LoginServerState::new(LoginStubData::new());
|
|
||||||
common::mainloop::mainloop(auth_state, login::login::LOGIN_PORT);
|
|
||||||
});
|
|
||||||
let char_thread = thread::spawn(|| {
|
|
||||||
let char_state = CharacterServerState::new(LoginStubData::new());
|
|
||||||
common::mainloop::mainloop(char_state, login::character::CHARACTER_PORT);
|
|
||||||
});
|
|
||||||
|
|
||||||
auth_thread.join().unwrap();
|
|
||||||
char_thread.join().unwrap();
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
#![feature(const_generics)]
|
|
||||||
|
|
||||||
mod common;
|
|
||||||
mod patch;
|
|
||||||
use crate::patch::patch::{PatchServerState, PatchTreeIterItem, generate_patch_tree, load_config, load_motd};
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
println!("[patch] starting server");
|
|
||||||
|
|
||||||
let patch_config = load_config();
|
|
||||||
let patch_motd: String = load_motd();
|
|
||||||
|
|
||||||
if let Err(_) = std::fs::read_dir(patch_config.path.as_str()) {
|
|
||||||
println!("Patch directory {} does not exist. Attempting to create it...", patch_config.path.as_str());
|
|
||||||
if let Err(err) = std::fs::create_dir(patch_config.path.as_str()) {
|
|
||||||
panic!("Failed to create patch directory! \n{}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let (patch_file_tree, patch_file_lookup) = generate_patch_tree(patch_config.path.as_str());
|
|
||||||
println!("[patch] files to patch:");
|
|
||||||
let mut indent = 0;
|
|
||||||
for item in patch_file_tree.flatten() {
|
|
||||||
match item {
|
|
||||||
PatchTreeIterItem::Directory(path) => {
|
|
||||||
let s = path.to_str().unwrap();
|
|
||||||
println!("{: >2$}\u{2517}\u{2500}\u{2500} {}", "", s, indent * 4);
|
|
||||||
indent += 1;
|
|
||||||
},
|
|
||||||
PatchTreeIterItem::File(path, id) => {
|
|
||||||
let s = path.to_str().unwrap();
|
|
||||||
println!("{: >3$}\u{2520}\u{2500}\u{2500} {} ({})", "", s, id, indent * 4);
|
|
||||||
},
|
|
||||||
PatchTreeIterItem::UpDirectory => {
|
|
||||||
indent -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let patch_state = PatchServerState::new(patch_file_tree, patch_file_lookup, patch_motd);
|
|
||||||
common::mainloop::mainloop(patch_state, patch_config.port);
|
|
||||||
|
|
||||||
println!("[patch] exiting...");
|
|
||||||
}
|
|
@ -215,7 +215,7 @@ impl ItemManager {
|
|||||||
let inventory = self.character_inventory.get_mut(&character.id).unwrap();
|
let inventory = self.character_inventory.get_mut(&character.id).unwrap();
|
||||||
inventory.initialize_item_ids(base_inventory_id);
|
inventory.initialize_item_ids(base_inventory_id);
|
||||||
let base_bank_id = ((area_client.local_client.id() as u32) << 21) | 0x20000;
|
let base_bank_id = ((area_client.local_client.id() as u32) << 21) | 0x20000;
|
||||||
let default_bank = self.character_bank.get_mut(&character.id);//.unwrap().get_mut(&BankName("".to_string()));
|
let default_bank = self.character_bank.get_mut(&character.id);
|
||||||
match default_bank {
|
match default_bank {
|
||||||
Some(default_bank) => {
|
Some(default_bank) => {
|
||||||
default_bank.initialize_item_ids(base_bank_id);
|
default_bank.initialize_item_ids(base_bank_id);
|
||||||
@ -933,16 +933,8 @@ impl ItemManager {
|
|||||||
character_id: character.id,
|
character_id: character.id,
|
||||||
slot: slot,
|
slot: slot,
|
||||||
equipped: true,
|
equipped: true,
|
||||||
}).await;
|
}).await?;
|
||||||
entity_gateway.save_item(&ItemEntity{
|
entity_gateway.change_item(&inventory_item.entity_id, &inventory_item.item).await?;
|
||||||
id: inventory_item.entity_id,
|
|
||||||
location: ItemLocation::Inventory{
|
|
||||||
character_id: character.id,
|
|
||||||
slot: slot,
|
|
||||||
equipped: true,
|
|
||||||
},
|
|
||||||
item: inventory_item.item.clone(),
|
|
||||||
}).await;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -968,15 +960,7 @@ impl ItemManager {
|
|||||||
slot: slot,
|
slot: slot,
|
||||||
equipped: false,
|
equipped: false,
|
||||||
}).await;
|
}).await;
|
||||||
entity_gateway.save_item(&ItemEntity{
|
entity_gateway.change_item(&inventory_item.entity_id, &inventory_item.item).await?;
|
||||||
id: inventory_item.entity_id,
|
|
||||||
location: ItemLocation::Inventory{
|
|
||||||
character_id: character.id,
|
|
||||||
slot: slot,
|
|
||||||
equipped: false,
|
|
||||||
},
|
|
||||||
item: inventory_item.item.clone(),
|
|
||||||
}).await;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ pub enum MonsterParseError {
|
|||||||
UnknownMonster(String),
|
UnknownMonster(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct MonsterStatError;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Copy, Clone, Hash, Eq, PartialEq, enum_utils::FromStr, derive_more::Display)]
|
#[derive(Debug, Serialize, Deserialize, Copy, Clone, Hash, Eq, PartialEq, enum_utils::FromStr, derive_more::Display)]
|
||||||
pub enum MonsterType {
|
pub enum MonsterType {
|
||||||
@ -175,40 +176,37 @@ fn load_battle_param(filename: &str) -> HashMap<MonsterType, MonsterStats> {
|
|||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_monster_stats_table(mode: &RoomMode) -> HashMap<MonsterType, MonsterStats> {
|
pub fn load_monster_stats_table(mode: &RoomMode) -> Result<HashMap<MonsterType, MonsterStats>, MonsterStatError> {
|
||||||
match mode {
|
match mode {
|
||||||
RoomMode::Multi {episode: Episode::One, difficulty: Difficulty::Normal} => load_battle_param("ep1_multi_normal.toml"),
|
RoomMode::Multi {episode: Episode::One, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep1_multi_normal.toml")),
|
||||||
RoomMode::Multi {episode: Episode::One, difficulty: Difficulty::Hard} => load_battle_param("ep1_multi_hard.toml"),
|
RoomMode::Multi {episode: Episode::One, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep1_multi_hard.toml")),
|
||||||
RoomMode::Multi {episode: Episode::One, difficulty: Difficulty::VeryHard} => load_battle_param("ep1_multi_veryhard.toml"),
|
RoomMode::Multi {episode: Episode::One, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep1_multi_veryhard.toml")),
|
||||||
RoomMode::Multi {episode: Episode::One, difficulty: Difficulty::Ultimate} => load_battle_param("ep1_multi_ultimate.toml"),
|
RoomMode::Multi {episode: Episode::One, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep1_multi_ultimate.toml")),
|
||||||
|
|
||||||
RoomMode::Multi {episode: Episode::Two, difficulty: Difficulty::Normal} => load_battle_param("ep2_multi_normal.toml"),
|
RoomMode::Multi {episode: Episode::Two, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep2_multi_normal.toml")),
|
||||||
RoomMode::Multi {episode: Episode::Two, difficulty: Difficulty::Hard} => load_battle_param("ep2_multi_hard.toml"),
|
RoomMode::Multi {episode: Episode::Two, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep2_multi_hard.toml")),
|
||||||
RoomMode::Multi {episode: Episode::Two, difficulty: Difficulty::VeryHard} => load_battle_param("ep2_multi_veryhard.toml"),
|
RoomMode::Multi {episode: Episode::Two, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep2_multi_veryhard.toml")),
|
||||||
RoomMode::Multi {episode: Episode::Two, difficulty: Difficulty::Ultimate} => load_battle_param("ep2_multi_ultimate.toml"),
|
RoomMode::Multi {episode: Episode::Two, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep2_multi_ultimate.toml")),
|
||||||
|
|
||||||
RoomMode::Multi {episode: Episode::Four, difficulty: Difficulty::Normal} => load_battle_param("ep4_multi_normal.toml"),
|
RoomMode::Multi {episode: Episode::Four, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep4_multi_normal.toml")),
|
||||||
RoomMode::Multi {episode: Episode::Four, difficulty: Difficulty::Hard} => load_battle_param("ep4_multi_hard.toml"),
|
RoomMode::Multi {episode: Episode::Four, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep4_multi_hard.toml")),
|
||||||
RoomMode::Multi {episode: Episode::Four, difficulty: Difficulty::VeryHard} => load_battle_param("ep4_multi_veryhard.toml"),
|
RoomMode::Multi {episode: Episode::Four, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep4_multi_veryhard.toml")),
|
||||||
RoomMode::Multi {episode: Episode::Four, difficulty: Difficulty::Ultimate} => load_battle_param("ep4_multi_ultimate.toml"),
|
RoomMode::Multi {episode: Episode::Four, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep4_multi_ultimate.toml")),
|
||||||
|
|
||||||
|
RoomMode::Single {episode: Episode::One, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep1_solo_normal.toml")),
|
||||||
|
RoomMode::Single {episode: Episode::One, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep1_solo_hard.toml")),
|
||||||
|
RoomMode::Single {episode: Episode::One, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep1_solo_veryhard.toml")),
|
||||||
|
RoomMode::Single {episode: Episode::One, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep1_solo_ultimate.toml")),
|
||||||
|
|
||||||
|
RoomMode::Single {episode: Episode::Two, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep2_solo_normal.toml")),
|
||||||
|
RoomMode::Single {episode: Episode::Two, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep2_solo_hard.toml")),
|
||||||
|
RoomMode::Single {episode: Episode::Two, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep2_solo_veryhard.toml")),
|
||||||
|
RoomMode::Single {episode: Episode::Two, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep2_solo_ultimate.toml")),
|
||||||
|
|
||||||
|
RoomMode::Single {episode: Episode::Four, difficulty: Difficulty::Normal} => Ok(load_battle_param("ep4_solo_normal.toml")),
|
||||||
RoomMode::Single {episode: Episode::One, difficulty: Difficulty::Normal} => load_battle_param("ep1_solo_normal.toml"),
|
RoomMode::Single {episode: Episode::Four, difficulty: Difficulty::Hard} => Ok(load_battle_param("ep4_solo_hard.toml")),
|
||||||
RoomMode::Single {episode: Episode::One, difficulty: Difficulty::Hard} => load_battle_param("ep1_solo_hard.toml"),
|
RoomMode::Single {episode: Episode::Four, difficulty: Difficulty::VeryHard} => Ok(load_battle_param("ep4_solo_veryhard.toml")),
|
||||||
RoomMode::Single {episode: Episode::One, difficulty: Difficulty::VeryHard} => load_battle_param("ep1_solo_veryhard.toml"),
|
RoomMode::Single {episode: Episode::Four, difficulty: Difficulty::Ultimate} => Ok(load_battle_param("ep4_solo_ultimate.toml")),
|
||||||
RoomMode::Single {episode: Episode::One, difficulty: Difficulty::Ultimate} => load_battle_param("ep1_solo_ultimate.toml"),
|
_ => Err(MonsterStatError),
|
||||||
|
|
||||||
RoomMode::Single {episode: Episode::Two, difficulty: Difficulty::Normal} => load_battle_param("ep2_solo_normal.toml"),
|
|
||||||
RoomMode::Single {episode: Episode::Two, difficulty: Difficulty::Hard} => load_battle_param("ep2_solo_hard.toml"),
|
|
||||||
RoomMode::Single {episode: Episode::Two, difficulty: Difficulty::VeryHard} => load_battle_param("ep2_solo_veryhard.toml"),
|
|
||||||
RoomMode::Single {episode: Episode::Two, difficulty: Difficulty::Ultimate} => load_battle_param("ep2_solo_ultimate.toml"),
|
|
||||||
|
|
||||||
RoomMode::Single {episode: Episode::Four, difficulty: Difficulty::Normal} => load_battle_param("ep4_solo_normal.toml"),
|
|
||||||
RoomMode::Single {episode: Episode::Four, difficulty: Difficulty::Hard} => load_battle_param("ep4_solo_hard.toml"),
|
|
||||||
RoomMode::Single {episode: Episode::Four, difficulty: Difficulty::VeryHard} => load_battle_param("ep4_solo_veryhard.toml"),
|
|
||||||
RoomMode::Single {episode: Episode::Four, difficulty: Difficulty::Ultimate} => load_battle_param("ep4_solo_ultimate.toml"),
|
|
||||||
_ => panic!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,6 @@ where
|
|||||||
let client_and_drop = clients_in_area.into_iter()
|
let client_and_drop = clients_in_area.into_iter()
|
||||||
.filter_map(|area_client| {
|
.filter_map(|area_client| {
|
||||||
room.drop_table.get_drop(&monster.map_area, &monster.monster).map(|item_drop_type| {
|
room.drop_table.get_drop(&monster.map_area, &monster.monster).map(|item_drop_type| {
|
||||||
warn!("drop is? {:?}", item_drop_type);
|
|
||||||
(area_client, item_drop_type)
|
(area_client, item_drop_type)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@ -183,7 +182,6 @@ EG: EntityGateway
|
|||||||
let client_and_drop = clients_in_area.into_iter()
|
let client_and_drop = clients_in_area.into_iter()
|
||||||
.filter_map(|area_client| {
|
.filter_map(|area_client| {
|
||||||
room.drop_table.get_box_drop(&box_object.map, &box_object).map(|item_drop_type| {
|
room.drop_table.get_box_drop(&box_object.map, &box_object).map(|item_drop_type| {
|
||||||
warn!("drop is? {:?}", item_drop_type);
|
|
||||||
(area_client, item_drop_type)
|
(area_client, item_drop_type)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
@ -26,7 +26,7 @@ pub async fn request_exp<EG: EntityGateway>(id: ClientId,
|
|||||||
.ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?;
|
.ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?;
|
||||||
|
|
||||||
let monster = room.maps.enemy_by_id(request_exp.enemy_id as usize)?;
|
let monster = room.maps.enemy_by_id(request_exp.enemy_id as usize)?;
|
||||||
let monster_stats = room.monster_stats.get(&monster.monster).unwrap();
|
let monster_stats = room.monster_stats.get(&monster.monster).ok_or(ShipError::UnknownMonster(monster.monster.clone()))?;
|
||||||
|
|
||||||
let exp_gain = if request_exp.last_hitter == 1 {
|
let exp_gain = if request_exp.last_hitter == 1 {
|
||||||
monster_stats.exp
|
monster_stats.exp
|
||||||
|
@ -77,6 +77,9 @@ pub fn join_room(id: ClientId,
|
|||||||
|
|
||||||
let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||||
let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?;
|
let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||||
|
|
||||||
|
item_manager.add_character_to_room(room_id, &client.character, area_client);
|
||||||
|
|
||||||
let leader = client_location.get_room_leader(room_id).map_err(|err| -> ClientLocationError { err.into() })?;
|
let leader = client_location.get_room_leader(room_id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||||
let join_room = builder::room::join_room(id, clients, client_location, room_id, &room)?;
|
let join_room = builder::room::join_room(id, clients, client_location, room_id, &room)?;
|
||||||
let add_to = builder::room::add_to_room(id, &client, &area_client, &leader, item_manager, level_table, room_id)?;
|
let add_to = builder::room::add_to_room(id, &client, &area_client, &leader, item_manager, level_table, room_id)?;
|
||||||
@ -84,8 +87,6 @@ pub fn join_room(id: ClientId,
|
|||||||
let room = rooms.get_mut(room_id.0).unwrap().as_mut().unwrap();
|
let room = rooms.get_mut(room_id.0).unwrap().as_mut().unwrap();
|
||||||
room.bursting = true;
|
room.bursting = true;
|
||||||
|
|
||||||
item_manager.add_character_to_room(room_id, &client.character, area_client);
|
|
||||||
|
|
||||||
let mut result: Box<dyn Iterator<Item=(ClientId, SendShipPacket)> + Send> = Box::new(
|
let mut result: Box<dyn Iterator<Item=(ClientId, SendShipPacket)> + Send> = Box::new(
|
||||||
vec![(id, SendShipPacket::JoinRoom(join_room))]
|
vec![(id, SendShipPacket::JoinRoom(join_room))]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -13,6 +13,7 @@ pub enum RoomCreationError {
|
|||||||
InvalidMode,
|
InvalidMode,
|
||||||
InvalidEpisode(u8),
|
InvalidEpisode(u8),
|
||||||
InvalidDifficulty(u8),
|
InvalidDifficulty(u8),
|
||||||
|
CouldNotLoadMonsterStats(RoomMode),
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +232,7 @@ impl RoomState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ok(RoomState {
|
Ok(RoomState {
|
||||||
monster_stats: Box::new(load_monster_stats_table(&room_mode)),
|
monster_stats: Box::new(load_monster_stats_table(&room_mode).map_err(|_| RoomCreationError::CouldNotLoadMonsterStats(room_mode.clone()))?),
|
||||||
mode: room_mode,
|
mode: room_mode,
|
||||||
random_seed: rand::thread_rng().gen(),
|
random_seed: rand::thread_rng().gen(),
|
||||||
name: String::from_utf16_lossy(&create_room.name).trim_matches(char::from(0)).into(),
|
name: String::from_utf16_lossy(&create_room.name).trim_matches(char::from(0)).into(),
|
||||||
|
105
src/ship/ship.rs
105
src/ship/ship.rs
@ -22,7 +22,7 @@ use crate::entity::gateway::{EntityGateway, GatewayError};
|
|||||||
use crate::entity::account::{UserAccountEntity, UserSettingsEntity};
|
use crate::entity::account::{UserAccountEntity, UserSettingsEntity};
|
||||||
use crate::entity::character::{CharacterEntity, SectionID};
|
use crate::entity::character::{CharacterEntity, SectionID};
|
||||||
|
|
||||||
use crate::ship::location::{ClientLocation, RoomLobby, MAX_ROOMS, ClientLocationError};
|
use crate::ship::location::{ClientLocation, RoomLobby, MAX_ROOMS, ClientLocationError, GetNeighborError, GetClientsError, GetAreaError};
|
||||||
|
|
||||||
use crate::ship::items;
|
use crate::ship::items;
|
||||||
use crate::ship::room;
|
use crate::ship::room;
|
||||||
@ -45,6 +45,9 @@ pub enum ShipError {
|
|||||||
InvalidSlot(ClientId, u32),
|
InvalidSlot(ClientId, u32),
|
||||||
TooManyClients,
|
TooManyClients,
|
||||||
ClientLocationError(#[from] ClientLocationError),
|
ClientLocationError(#[from] ClientLocationError),
|
||||||
|
GetNeighborError(#[from] GetNeighborError),
|
||||||
|
GetClientsError(#[from] GetClientsError),
|
||||||
|
GetAreaError(#[from] GetAreaError),
|
||||||
MapsError(#[from] MapsError),
|
MapsError(#[from] MapsError),
|
||||||
MapAreaError(#[from] MapAreaError),
|
MapAreaError(#[from] MapAreaError),
|
||||||
InvalidRoom(u32),
|
InvalidRoom(u32),
|
||||||
@ -63,6 +66,7 @@ pub enum ShipError {
|
|||||||
NotEnoughMeseta(ClientId, u32),
|
NotEnoughMeseta(ClientId, u32),
|
||||||
ShopError,
|
ShopError,
|
||||||
GatewayError(#[from] GatewayError),
|
GatewayError(#[from] GatewayError),
|
||||||
|
UnknownMonster(crate::ship::monster::MonsterType),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -294,6 +298,7 @@ pub struct ShipServerStateBuilder<EG: EntityGateway> {
|
|||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
ip: Option<Ipv4Addr>,
|
ip: Option<Ipv4Addr>,
|
||||||
port: Option<u16>,
|
port: Option<u16>,
|
||||||
|
auth_token: Option<AuthToken>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<EG: EntityGateway> ShipServerStateBuilder<EG> {
|
impl<EG: EntityGateway> ShipServerStateBuilder<EG> {
|
||||||
@ -303,6 +308,7 @@ impl<EG: EntityGateway> ShipServerStateBuilder<EG> {
|
|||||||
name: None,
|
name: None,
|
||||||
ip: None,
|
ip: None,
|
||||||
port: None,
|
port: None,
|
||||||
|
auth_token: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,6 +332,11 @@ impl<EG: EntityGateway> ShipServerStateBuilder<EG> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn auth_token(mut self, auth_token: AuthToken) -> ShipServerStateBuilder<EG> {
|
||||||
|
self.auth_token = Some(auth_token);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build(self) -> ShipServerState<EG> {
|
pub fn build(self) -> ShipServerState<EG> {
|
||||||
ShipServerState {
|
ShipServerState {
|
||||||
entity_gateway: self.entity_gateway.unwrap(),
|
entity_gateway: self.entity_gateway.unwrap(),
|
||||||
@ -339,6 +350,7 @@ impl<EG: EntityGateway> ShipServerStateBuilder<EG> {
|
|||||||
ip: self.ip.unwrap_or(Ipv4Addr::new(127,0,0,1)),
|
ip: self.ip.unwrap_or(Ipv4Addr::new(127,0,0,1)),
|
||||||
port: self.port.unwrap_or(SHIP_PORT),
|
port: self.port.unwrap_or(SHIP_PORT),
|
||||||
shops: Box::new(ItemShops::new()),
|
shops: Box::new(ItemShops::new()),
|
||||||
|
auth_token: self.auth_token.unwrap_or(AuthToken("".into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -355,6 +367,7 @@ pub struct ShipServerState<EG: EntityGateway> {
|
|||||||
ip: Ipv4Addr,
|
ip: Ipv4Addr,
|
||||||
port: u16,
|
port: u16,
|
||||||
shops: Box<ItemShops>,
|
shops: Box<ItemShops>,
|
||||||
|
auth_token: AuthToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<EG: EntityGateway> ShipServerState<EG> {
|
impl<EG: EntityGateway> ShipServerState<EG> {
|
||||||
@ -362,93 +375,93 @@ impl<EG: EntityGateway> ShipServerState<EG> {
|
|||||||
ShipServerStateBuilder::new()
|
ShipServerStateBuilder::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn message(&mut self, id: ClientId, msg: &Message) -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> {
|
async fn message(&mut self, id: ClientId, msg: &Message) -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error> {
|
||||||
match &msg.msg {
|
Ok(match &msg.msg {
|
||||||
GameMessage::RequestExp(request_exp) => {
|
GameMessage::RequestExp(request_exp) => {
|
||||||
handler::message::request_exp(id, request_exp, &mut self.entity_gateway, &self.client_location, &mut self.clients, &mut self.rooms, &self.level_table).await
|
handler::message::request_exp(id, request_exp, &mut self.entity_gateway, &self.client_location, &mut self.clients, &mut self.rooms, &self.level_table).await?
|
||||||
},
|
},
|
||||||
GameMessage::PlayerDropItem(player_drop_item) => {
|
GameMessage::PlayerDropItem(player_drop_item) => {
|
||||||
handler::message::player_drop_item(id, player_drop_item, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.rooms, &mut self.item_manager).await
|
handler::message::player_drop_item(id, player_drop_item, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.rooms, &mut self.item_manager).await?
|
||||||
},
|
},
|
||||||
GameMessage::DropCoordinates(drop_coordinates) => {
|
GameMessage::DropCoordinates(drop_coordinates) => {
|
||||||
handler::message::drop_coordinates(id, drop_coordinates, &self.client_location, &mut self.clients, &self.rooms)
|
handler::message::drop_coordinates(id, drop_coordinates, &self.client_location, &mut self.clients, &self.rooms)?
|
||||||
},
|
},
|
||||||
GameMessage::PlayerNoLongerHasItem(no_longer_has_item) => {
|
GameMessage::PlayerNoLongerHasItem(no_longer_has_item) => {
|
||||||
handler::message::split_item_stack(id, no_longer_has_item, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.item_manager).await
|
handler::message::split_item_stack(id, no_longer_has_item, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.item_manager).await?
|
||||||
},
|
},
|
||||||
GameMessage::PlayerChangedMap(_) | GameMessage::PlayerChangedMap2(_) | GameMessage::TellOtherPlayerMyLocation(_) |
|
GameMessage::PlayerChangedMap(_) | GameMessage::PlayerChangedMap2(_) | GameMessage::TellOtherPlayerMyLocation(_) |
|
||||||
GameMessage::PlayerWarpingToFloor(_) | GameMessage::PlayerTeleported(_) | GameMessage::PlayerStopped(_) |
|
GameMessage::PlayerWarpingToFloor(_) | GameMessage::PlayerTeleported(_) | GameMessage::PlayerStopped(_) |
|
||||||
GameMessage::PlayerLoadedIn(_) | GameMessage::PlayerWalking(_) | GameMessage::PlayerRunning(_) |
|
GameMessage::PlayerLoadedIn(_) | GameMessage::PlayerWalking(_) | GameMessage::PlayerRunning(_) |
|
||||||
GameMessage::PlayerWarped(_) | GameMessage::PlayerChangedFloor(_) | GameMessage::InitializeSpeechNpc(_) => {
|
GameMessage::PlayerWarped(_) | GameMessage::PlayerChangedFloor(_) | GameMessage::InitializeSpeechNpc(_) => {
|
||||||
handler::message::update_player_position(id, &msg, &mut self.clients, &mut self.client_location, &self.rooms)
|
handler::message::update_player_position(id, &msg, &mut self.clients, &mut self.client_location, &self.rooms)?
|
||||||
},
|
},
|
||||||
GameMessage::ChargeAttack(charge_attack) => {
|
GameMessage::ChargeAttack(charge_attack) => {
|
||||||
handler::message::charge_attack(id, charge_attack, &mut self.clients, &mut self.entity_gateway).await
|
handler::message::charge_attack(id, charge_attack, &mut self.clients, &mut self.entity_gateway).await?
|
||||||
},
|
},
|
||||||
GameMessage::PlayerUseItem(player_use_item) => {
|
GameMessage::PlayerUseItem(player_use_item) => {
|
||||||
handler::message::use_item(id, player_use_item, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.item_manager).await
|
handler::message::use_item(id, player_use_item, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.item_manager).await?
|
||||||
},
|
},
|
||||||
GameMessage::PlayerUsedMedicalCenter(player_used_medical_center) => {
|
GameMessage::PlayerUsedMedicalCenter(player_used_medical_center) => {
|
||||||
handler::message::player_used_medical_center(id, &player_used_medical_center, &mut self.entity_gateway, &mut self.clients).await
|
handler::message::player_used_medical_center(id, &player_used_medical_center, &mut self.entity_gateway, &mut self.clients).await?
|
||||||
},
|
},
|
||||||
GameMessage::PlayerFeedMag(player_feed_mag) => {
|
GameMessage::PlayerFeedMag(player_feed_mag) => {
|
||||||
handler::message::player_feed_mag(id, &player_feed_mag, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.item_manager).await
|
handler::message::player_feed_mag(id, &player_feed_mag, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.item_manager).await?
|
||||||
},
|
},
|
||||||
GameMessage::PlayerEquipItem(player_equip_item) => {
|
GameMessage::PlayerEquipItem(player_equip_item) => {
|
||||||
handler::message::player_equips_item(id, &player_equip_item, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await
|
handler::message::player_equips_item(id, &player_equip_item, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await?
|
||||||
},
|
},
|
||||||
GameMessage::PlayerUnequipItem(player_unequip_item) => {
|
GameMessage::PlayerUnequipItem(player_unequip_item) => {
|
||||||
handler::message::player_unequips_item(id, &player_unequip_item, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await
|
handler::message::player_unequips_item(id, &player_unequip_item, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await?
|
||||||
},
|
},
|
||||||
GameMessage::SortItems(sort_items) => {
|
GameMessage::SortItems(sort_items) => {
|
||||||
handler::message::player_sorts_items(id, sort_items, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await
|
handler::message::player_sorts_items(id, sort_items, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await?
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let cmsg = msg.clone();
|
let cmsg = msg.clone();
|
||||||
Ok(Box::new(self.client_location.get_client_neighbors(id).unwrap().into_iter()
|
Box::new(self.client_location.get_client_neighbors(id).unwrap().into_iter()
|
||||||
.map(move |client| {
|
.map(move |client| {
|
||||||
(client.client, SendShipPacket::Message(cmsg.clone()))
|
(client.client, SendShipPacket::Message(cmsg.clone()))
|
||||||
})))
|
}))
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn direct_message(&mut self, id: ClientId, msg: &DirectMessage) -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> {
|
async fn direct_message(&mut self, id: ClientId, msg: &DirectMessage) -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error> {
|
||||||
let target = msg.flag;
|
let target = msg.flag;
|
||||||
match &msg.msg {
|
Ok(match &msg.msg {
|
||||||
GameMessage::GuildcardSend(guildcard_send) => {
|
GameMessage::GuildcardSend(guildcard_send) => {
|
||||||
Ok(handler::direct_message::guildcard_send(id, guildcard_send, target, &self.client_location, &self.clients))
|
handler::direct_message::guildcard_send(id, guildcard_send, target, &self.client_location, &self.clients)
|
||||||
},
|
},
|
||||||
GameMessage::RequestItem(request_item) => {
|
GameMessage::RequestItem(request_item) => {
|
||||||
handler::direct_message::request_item(id, request_item, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.rooms, &mut self.item_manager).await
|
handler::direct_message::request_item(id, request_item, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.rooms, &mut self.item_manager).await?
|
||||||
},
|
},
|
||||||
GameMessage::PickupItem(pickup_item) => {
|
GameMessage::PickupItem(pickup_item) => {
|
||||||
handler::direct_message::pickup_item(id, pickup_item, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.item_manager).await
|
handler::direct_message::pickup_item(id, pickup_item, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.item_manager).await?
|
||||||
},
|
},
|
||||||
GameMessage::BoxDropRequest(box_drop_request) => {
|
GameMessage::BoxDropRequest(box_drop_request) => {
|
||||||
handler::direct_message::request_box_item(id, box_drop_request, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.rooms, &mut self.item_manager).await
|
handler::direct_message::request_box_item(id, box_drop_request, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.rooms, &mut self.item_manager).await?
|
||||||
},
|
},
|
||||||
GameMessage::BankRequest(_bank_request) => {
|
GameMessage::BankRequest(_bank_request) => {
|
||||||
handler::direct_message::send_bank_list(id, &self.clients, &mut self.item_manager).await
|
handler::direct_message::send_bank_list(id, &self.clients, &mut self.item_manager).await?
|
||||||
},
|
},
|
||||||
GameMessage::BankInteraction(bank_interaction) => {
|
GameMessage::BankInteraction(bank_interaction) => {
|
||||||
handler::direct_message::bank_interaction(id, bank_interaction, &mut self.entity_gateway, &self.client_location, &mut self.clients, &mut self.item_manager).await
|
handler::direct_message::bank_interaction(id, bank_interaction, &mut self.entity_gateway, &self.client_location, &mut self.clients, &mut self.item_manager).await?
|
||||||
},
|
},
|
||||||
GameMessage::ShopRequest(shop_request) => {
|
GameMessage::ShopRequest(shop_request) => {
|
||||||
handler::direct_message::shop_request(id, shop_request, &self.client_location, &mut self.clients, &self.rooms, &self.level_table, &mut self.shops).await
|
handler::direct_message::shop_request(id, shop_request, &self.client_location, &mut self.clients, &self.rooms, &self.level_table, &mut self.shops).await?
|
||||||
},
|
},
|
||||||
GameMessage::BuyItem(buy_item) => {
|
GameMessage::BuyItem(buy_item) => {
|
||||||
handler::direct_message::buy_item(id, buy_item, &mut self.entity_gateway, &self.client_location, &mut self.clients, &mut self.item_manager).await
|
handler::direct_message::buy_item(id, buy_item, &mut self.entity_gateway, &self.client_location, &mut self.clients, &mut self.item_manager).await?
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let cmsg = msg.clone();
|
let cmsg = msg.clone();
|
||||||
Ok(Box::new(self.client_location.get_all_clients_by_client(id).unwrap().into_iter()
|
Box::new(self.client_location.get_all_clients_by_client(id).unwrap().into_iter()
|
||||||
.filter(move |client| client.local_client.id() == target as u8)
|
.filter(move |client| client.local_client.id() == target as u8)
|
||||||
.map(move |client| {
|
.map(move |client| {
|
||||||
(client.client, SendShipPacket::DirectMessage(cmsg.clone()))
|
(client.client, SendShipPacket::DirectMessage(cmsg.clone()))
|
||||||
})))
|
}))
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,9 +469,9 @@ impl<EG: EntityGateway> ShipServerState<EG> {
|
|||||||
impl<EG: EntityGateway> ServerState for ShipServerState<EG> {
|
impl<EG: EntityGateway> ServerState for ShipServerState<EG> {
|
||||||
type SendPacket = SendShipPacket;
|
type SendPacket = SendShipPacket;
|
||||||
type RecvPacket = RecvShipPacket;
|
type RecvPacket = RecvShipPacket;
|
||||||
type PacketError = ShipError;
|
type PacketError = anyhow::Error;
|
||||||
|
|
||||||
async fn on_connect(&mut self, _id: ClientId) -> Result<Vec<OnConnect<Self::SendPacket>>, ShipError> {
|
async fn on_connect(&mut self, _id: ClientId) -> Result<Vec<OnConnect<Self::SendPacket>>, anyhow::Error> {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
let mut server_key = [0u8; 48];
|
let mut server_key = [0u8; 48];
|
||||||
@ -473,7 +486,7 @@ impl<EG: EntityGateway> ServerState for ShipServerState<EG> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn handle(&mut self, id: ClientId, pkt: &RecvShipPacket)
|
async fn handle(&mut self, id: ClientId, pkt: &RecvShipPacket)
|
||||||
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> {
|
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error> {
|
||||||
Ok(match pkt {
|
Ok(match pkt {
|
||||||
RecvShipPacket::Login(login) => {
|
RecvShipPacket::Login(login) => {
|
||||||
Box::new(handler::auth::validate_login(id, login, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager, &self.name).await?.into_iter().map(move |pkt| (id, pkt)))
|
Box::new(handler::auth::validate_login(id, login, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager, &self.name).await?.into_iter().map(move |pkt| (id, pkt)))
|
||||||
@ -580,13 +593,13 @@ impl<EG: EntityGateway> ServerState for ShipServerState<EG> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_disconnect(&mut self, id: ClientId) -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> {
|
async fn on_disconnect(&mut self, id: ClientId) -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> {
|
||||||
// TODO: don't unwrap!
|
// TODO: don't unwrap!
|
||||||
let client = self.clients.get(&id).unwrap();
|
let client = self.clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||||
let area_client = self.client_location.get_local_client(id).unwrap();
|
let area_client = self.client_location.get_local_client(id)?;
|
||||||
let neighbors = self.client_location.get_client_neighbors(id).unwrap();
|
let neighbors = self.client_location.get_client_neighbors(id)?;
|
||||||
|
|
||||||
let pkt = match self.client_location.get_area(id).unwrap() {
|
let pkt = match self.client_location.get_area(id)? {
|
||||||
RoomLobby::Room(room) => {
|
RoomLobby::Room(room) => {
|
||||||
if neighbors.len() == 0 {
|
if neighbors.len() == 0 {
|
||||||
self.rooms[room.0] = None;
|
self.rooms[room.0] = None;
|
||||||
@ -622,12 +635,14 @@ impl<EG: EntityGateway> InterserverActor for ShipServerState<EG> {
|
|||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
async fn on_connect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> {
|
async fn on_connect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> {
|
||||||
vec![ /* ShipMessage::Authenticate(AuthToken("hi".into())), */ (id, ShipMessage::NewShip(Ship {
|
vec![
|
||||||
name: self.name.clone(),
|
(id, ShipMessage::Authenticate(self.auth_token.clone())),
|
||||||
ip: self.ip.clone(),
|
(id, ShipMessage::NewShip(Ship {
|
||||||
port: self.port,
|
name: self.name.clone(),
|
||||||
block_count: 2,
|
ip: self.ip.clone(),
|
||||||
})) ]
|
port: self.port,
|
||||||
|
block_count: 2,
|
||||||
|
})) ]
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn action(&mut self, _id: ServerId, _msg: Self::RecvMessage) -> Result<Vec<(ServerId, Self::SendMessage)>, Self::Error> {
|
async fn action(&mut self, _id: ServerId, _msg: Self::RecvMessage) -> Result<Vec<(ServerId, Self::SendMessage)>, Self::Error> {
|
||||||
|
@ -59,6 +59,13 @@ pub async fn create_room<EG: EntityGateway>(ship: &mut ShipServerState<EG>, id:
|
|||||||
create_room_with_difficulty(ship, id, name, password, Difficulty::Normal).await;
|
create_room_with_difficulty(ship, id, name, password, Difficulty::Normal).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn leave_room<EG: EntityGateway>(ship: &mut ShipServerState<EG>, id: ClientId) {
|
||||||
|
ship.handle(id, &RecvShipPacket::LobbySelect(LobbySelect {
|
||||||
|
menu: 3,
|
||||||
|
lobby: 0,
|
||||||
|
})).await.unwrap().for_each(drop);
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn create_room_with_difficulty<EG: EntityGateway>(ship: &mut ShipServerState<EG>, id: ClientId, name: &str, password: &str, difficulty: Difficulty) {
|
pub async fn create_room_with_difficulty<EG: EntityGateway>(ship: &mut ShipServerState<EG>, id: ClientId, name: &str, password: &str, difficulty: Difficulty) {
|
||||||
ship.handle(id, &RecvShipPacket::CreateRoom(CreateRoom {
|
ship.handle(id, &RecvShipPacket::CreateRoom(CreateRoom {
|
||||||
unknown: [0; 2],
|
unknown: [0; 2],
|
||||||
@ -79,4 +86,5 @@ pub async fn join_room<EG: EntityGateway>(ship: &mut ShipServerState<EG>, id: Cl
|
|||||||
menu: ROOM_MENU_ID,
|
menu: ROOM_MENU_ID,
|
||||||
item: room_id,
|
item: room_id,
|
||||||
})).await.unwrap().for_each(drop);
|
})).await.unwrap().for_each(drop);
|
||||||
|
ship.handle(id, &RecvShipPacket::DoneBursting(DoneBursting {})).await.unwrap().for_each(drop);
|
||||||
}
|
}
|
||||||
|
104
tests/test_rooms.rs
Normal file
104
tests/test_rooms.rs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
use elseware::common::serverstate::{ClientId, ServerState};
|
||||||
|
use elseware::entity::gateway::{EntityGateway, InMemoryGateway};
|
||||||
|
use elseware::entity::item;
|
||||||
|
use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket};
|
||||||
|
|
||||||
|
use libpso::packet::ship::*;
|
||||||
|
use libpso::packet::messages::*;
|
||||||
|
|
||||||
|
#[path = "common.rs"]
|
||||||
|
mod common;
|
||||||
|
use common::*;
|
||||||
|
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_item_ids_reset_when_rejoining_rooms() {
|
||||||
|
let mut entity_gateway = InMemoryGateway::new();
|
||||||
|
|
||||||
|
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
|
||||||
|
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a").await;
|
||||||
|
|
||||||
|
for slot in 0..3 {
|
||||||
|
entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Weapon(
|
||||||
|
item::weapon::Weapon {
|
||||||
|
weapon: item::weapon::WeaponType::Saber,
|
||||||
|
grind: 0,
|
||||||
|
special: None,
|
||||||
|
attrs: [None, None, None],
|
||||||
|
tekked: true,
|
||||||
|
modifiers: Vec::new(),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
location: item::ItemLocation::Inventory {
|
||||||
|
character_id: char1.id,
|
||||||
|
slot: slot,
|
||||||
|
equipped: false,
|
||||||
|
}
|
||||||
|
}).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
for slot in 0..10 {
|
||||||
|
entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Weapon(
|
||||||
|
item::weapon::Weapon {
|
||||||
|
weapon: item::weapon::WeaponType::Saber,
|
||||||
|
grind: 0,
|
||||||
|
special: None,
|
||||||
|
attrs: [None, None, None],
|
||||||
|
tekked: true,
|
||||||
|
modifiers: Vec::new(),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
location: item::ItemLocation::Inventory {
|
||||||
|
character_id: char2.id,
|
||||||
|
slot: slot,
|
||||||
|
equipped: false,
|
||||||
|
}
|
||||||
|
}).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
join_lobby(&mut ship, ClientId(2)).await;
|
||||||
|
|
||||||
|
create_room(&mut ship, ClientId(1), "room", "").await;
|
||||||
|
let p = ship.handle(ClientId(2), &RecvShipPacket::MenuSelect(MenuSelect {
|
||||||
|
menu: ROOM_MENU_ID,
|
||||||
|
item: 0,
|
||||||
|
})).await.unwrap().collect::<Vec<_>>();
|
||||||
|
ship.handle(ClientId(2), &RecvShipPacket::DoneBursting(DoneBursting {})).await.unwrap().for_each(drop);
|
||||||
|
|
||||||
|
match &p[1].1 {
|
||||||
|
SendShipPacket::AddToRoom(add_to) => {
|
||||||
|
println!("addto {:?}", add_to);
|
||||||
|
assert_eq!(add_to.playerinfo.inventory.items.iter().map(|k| k.item_id).collect::<Vec<_>>(),
|
||||||
|
vec![0x210000,0x210001,0x210002,0x210003,0x210004,0x210005,0x210006,0x210007,0x210008,0x210009,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
|
||||||
|
},
|
||||||
|
_ => panic!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
leave_room(&mut ship, ClientId(2)).await;
|
||||||
|
|
||||||
|
let p = ship.handle(ClientId(2), &RecvShipPacket::MenuSelect(MenuSelect {
|
||||||
|
menu: ROOM_MENU_ID,
|
||||||
|
item: 0,
|
||||||
|
})).await.unwrap().collect::<Vec<_>>();
|
||||||
|
|
||||||
|
match &p[1].1 {
|
||||||
|
SendShipPacket::AddToRoom(add_to) => {
|
||||||
|
assert_eq!(add_to.playerinfo.inventory.items.iter().map(|k| k.item_id).collect::<Vec<_>>(),
|
||||||
|
vec![0x210000,0x210001,0x210002,0x210003,0x210004,0x210005,0x210006,0x210007,0x210008,0x210009,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
|
||||||
|
},
|
||||||
|
_ => panic!(),
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user