Browse Source

cleanup this refactored mess

pull/121/head
jake 2 years ago
parent
commit
192ff967e6
  1. 1
      src/common/interserver.rs
  2. 18
      src/entity/gateway/postgres/models.rs
  3. 153
      src/login/character.rs
  4. 3
      src/patch/patch.rs
  5. 2
      src/ship/character.rs
  6. 14
      src/ship/items/actions.rs
  7. 96
      src/ship/items/state.rs
  8. 2
      src/ship/map/area.rs
  9. 2
      src/ship/packet/builder/lobby.rs
  10. 11
      src/ship/packet/handler/auth.rs
  11. 2
      src/ship/packet/handler/communication.rs
  12. 42
      src/ship/packet/handler/direct_message.rs
  13. 32
      src/ship/packet/handler/lobby.rs
  14. 10
      src/ship/packet/handler/message.rs
  15. 134
      src/ship/packet/handler/quest.rs
  16. 60
      src/ship/packet/handler/room.rs
  17. 2
      src/ship/packet/handler/ship.rs
  18. 12
      src/ship/packet/handler/trade.rs
  19. 44
      src/ship/room.rs
  20. 225
      src/ship/ship.rs
  21. 2
      src/ship/shops/armor.rs
  22. 6
      tests/test_exp_gain.rs

1
src/common/interserver.rs

@ -1,5 +1,4 @@
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
use async_std::sync::Arc;
use async_std::channel; use async_std::channel;
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;

18
src/entity/gateway/postgres/models.rs

@ -675,18 +675,18 @@ impl From<PgItemNoteDetail> for ItemNote {
fn from(other: PgItemNoteDetail) -> ItemNote { fn from(other: PgItemNoteDetail) -> ItemNote {
match other { match other {
PgItemNoteDetail::CharacterCreation{character_id} => ItemNote::CharacterCreation { PgItemNoteDetail::CharacterCreation{character_id} => ItemNote::CharacterCreation {
character_id: CharacterEntityId(character_id as u32),
character_id: CharacterEntityId(character_id),
}, },
PgItemNoteDetail::EnemyDrop{character_id, map_area, x, y, z} => ItemNote::EnemyDrop { PgItemNoteDetail::EnemyDrop{character_id, map_area, x, y, z} => ItemNote::EnemyDrop {
character_id: CharacterEntityId(character_id as u32),
character_id: CharacterEntityId(character_id),
map_area, map_area,
x,y,z, x,y,z,
}, },
PgItemNoteDetail::Pickup{character_id} => ItemNote::Pickup { PgItemNoteDetail::Pickup{character_id} => ItemNote::Pickup {
character_id: CharacterEntityId(character_id as u32),
character_id: CharacterEntityId(character_id),
}, },
PgItemNoteDetail::PlayerDrop{character_id, map_area, x, y, z} => ItemNote::PlayerDrop { PgItemNoteDetail::PlayerDrop{character_id, map_area, x, y, z} => ItemNote::PlayerDrop {
character_id: CharacterEntityId(character_id as u32),
character_id: CharacterEntityId(character_id),
map_area, map_area,
x,y,z, x,y,z,
}, },
@ -699,16 +699,16 @@ impl From<PgItemNoteDetail> for ItemNote {
}, },
PgItemNoteDetail::SoldToShop => ItemNote::SoldToShop, PgItemNoteDetail::SoldToShop => ItemNote::SoldToShop,
PgItemNoteDetail::Trade {trade_id, character_to, character_from} => ItemNote::Trade { PgItemNoteDetail::Trade {trade_id, character_to, character_from} => ItemNote::Trade {
trade_id: TradeId(trade_id as u32),
character_to: CharacterEntityId(character_to as u32),
character_from: CharacterEntityId(character_from as u32),
trade_id: TradeId(trade_id),
character_to: CharacterEntityId(character_to),
character_from: CharacterEntityId(character_from),
}, },
PgItemNoteDetail::Withdraw{character_id, bank} => ItemNote::Withdraw { PgItemNoteDetail::Withdraw{character_id, bank} => ItemNote::Withdraw {
character_id: CharacterEntityId(character_id as u32),
character_id: CharacterEntityId(character_id),
bank: BankName(bank), bank: BankName(bank),
}, },
PgItemNoteDetail::Deposit{character_id, bank} => ItemNote::Deposit { PgItemNoteDetail::Deposit{character_id, bank} => ItemNote::Deposit {
character_id: CharacterEntityId(character_id as u32),
character_id: CharacterEntityId(character_id),
bank: BankName(bank), bank: BankName(bank),
}, },
} }

153
src/login/character.rs

@ -2,7 +2,7 @@
use std::io::Read; use std::io::Read;
use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::collections::{BTreeMap, BTreeSet, HashMap};
use async_std::sync::Arc;
use async_std::sync::{Arc, RwLock};
use async_std::channel; use async_std::channel;
use rand::Rng; use rand::Rng;
@ -186,16 +186,14 @@ struct ConnectedClient {
pub struct CharacterServerState<EG: EntityGateway + Clone> { pub struct CharacterServerState<EG: EntityGateway + Clone> {
entity_gateway: EG, entity_gateway: EG,
param_header: ParamDataHeader, param_header: ParamDataHeader,
param_data: Vec<u8>,
clients: HashMap<ClientId, ClientState>,
ships: BTreeMap<ServerId, Ship>,
//level_table: CharacterLevelTable,
param_data: Arc<Vec<u8>>,
clients: Arc<RwLock<HashMap<ClientId, ClientState>>>,
ships: Arc<RwLock<BTreeMap<ServerId, Ship>>>,
auth_token: AuthToken, auth_token: AuthToken,
connected_clients: BTreeMap<UserAccountId, ConnectedClient>,
authenticated_ships: BTreeSet<ServerId>,
//ship_sender: BTreeMap<ServerId, Arc<Box<dyn Fn(LoginMessage) -> Box<dyn futures::future::Future<Output = ()>> + Send>>>,
ship_sender: BTreeMap<ServerId, channel::Sender<LoginMessage>>,
connected_clients: Arc<RwLock<BTreeMap<UserAccountId, ConnectedClient>>>,
authenticated_ships: Arc<RwLock<BTreeSet<ServerId>>>,
ship_sender: Arc<RwLock<BTreeMap<ServerId, channel::Sender<LoginMessage>>>>,
} }
@ -318,21 +316,21 @@ impl<EG: EntityGateway + Clone> CharacterServerState<EG> {
CharacterServerState { CharacterServerState {
entity_gateway, entity_gateway,
param_header, param_header,
param_data,
clients: HashMap::new(),
ships: BTreeMap::new(),
param_data: Arc::new(param_data),
clients: Default::default(),
ships: Default::default(),
//level_table: CharacterLevelTable::default(), //level_table: CharacterLevelTable::default(),
auth_token, auth_token,
authenticated_ships: BTreeSet::new(),
ship_sender: BTreeMap::new(),
connected_clients: BTreeMap::new(),
authenticated_ships: Default::default(),
ship_sender: Default::default(),
connected_clients: Default::default(),
} }
} }
async fn validate_login(&mut self, id: ClientId, pkt: &Login) -> Result<Vec<SendCharacterPacket>, anyhow::Error> { async fn validate_login(&mut self, id: ClientId, pkt: &Login) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
match get_login_status(&mut self.entity_gateway, pkt).await { match get_login_status(&mut self.entity_gateway, pkt).await {
Ok(user) => { Ok(user) => {
if let Some(connected_client) = self.connected_clients.get(&user.id) {
if let Some(connected_client) = self.connected_clients.read().await.get(&user.id) {
if let Some(expires) = connected_client.expires { if let Some(expires) = connected_client.expires {
if expires > chrono::Utc::now() { if expires > chrono::Utc::now() {
return Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(AccountStatus::AlreadyOnline, Session::new()))]); return Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(AccountStatus::AlreadyOnline, Session::new()))]);
@ -345,11 +343,12 @@ 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) as u32;
response.team_id = user.team_id.map_or(0, |ti| ti);
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
let mut client = self.clients.write().await;
let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?;
self.connected_clients.insert(user.id, ConnectedClient {
self.connected_clients.write().await.insert(user.id, ConnectedClient {
ship_id: None, ship_id: None,
expires: None, //Some(chrono::Utc::now() + chrono::Duration::minutes(1)), expires: None, //Some(chrono::Utc::now() + chrono::Duration::minutes(1)),
}); });
@ -364,9 +363,9 @@ impl<EG: EntityGateway + Clone> CharacterServerState<EG> {
} }
} }
fn send_ship_list(&mut self, _id: ClientId, _pkt: &Login) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
async 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.read().await.iter().map(|(i, s)| {
ShipListEntry { ShipListEntry {
menu: SHIP_MENU_ID, menu: SHIP_MENU_ID,
item: i.0 as u32, item: i.0 as u32,
@ -378,7 +377,8 @@ impl<EG: EntityGateway + Clone> CharacterServerState<EG> {
} }
async fn get_settings(&mut self, id: ClientId) -> Result<Vec<SendCharacterPacket>, anyhow::Error> { 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 mut client = self.clients.write().await;
let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?;
let user = client.user.as_ref().unwrap(); let user = client.user.as_ref().unwrap();
let settings = match self.entity_gateway.get_user_settings_by_user(user).await { let settings = match self.entity_gateway.get_user_settings_by_user(user).await {
@ -397,7 +397,8 @@ impl<EG: EntityGateway + Clone> CharacterServerState<EG> {
} }
async fn char_select(&mut self, id: ClientId, select: &CharSelect) -> Result<Vec<SendCharacterPacket>, anyhow::Error> { 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 mut client = self.clients.write().await;
let client = client.get_mut(&id).ok_or_else(|| 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)?);
} }
@ -443,7 +444,8 @@ impl<EG: EntityGateway + Clone> CharacterServerState<EG> {
} }
async fn guildcard_data_header(&mut self, id: ClientId) -> Result<Vec<SendCharacterPacket>, anyhow::Error> { 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 mut client = self.clients.write().await;
let client = client.get_mut(&id).ok_or_else(|| 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)?;
let bytes = guildcard_data.guildcard.as_bytes(); let bytes = guildcard_data.guildcard.as_bytes();
@ -454,15 +456,16 @@ impl<EG: EntityGateway + Clone> 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>, anyhow::Error> {
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
async fn guildcard_data_chunk(&mut self, id: ClientId, chunk: u32, again: u32) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
let mut client = self.clients.write().await;
let client = client.get_mut(&id).ok_or_else(|| 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;
let len = std::cmp::min(GUILD_CARD_CHUNK_SIZE, client.guildcard_data_buffer.as_ref().unwrap().len() as usize - start);
let len = std::cmp::min(GUILD_CARD_CHUNK_SIZE, client.guildcard_data_buffer.as_ref().unwrap().len() - start);
let end = start + len; let end = start + len;
let mut buf = [0u8; GUILD_CARD_CHUNK_SIZE as usize];
buf[..len as usize].copy_from_slice(&client.guildcard_data_buffer.as_ref().unwrap()[start..end]);
let mut buf = [0u8; GUILD_CARD_CHUNK_SIZE];
buf[..len].copy_from_slice(&client.guildcard_data_buffer.as_ref().unwrap()[start..end]);
vec![SendCharacterPacket::GuildcardDataChunk(Box::new(GuildcardDataChunk::new(chunk, buf, len)))] vec![SendCharacterPacket::GuildcardDataChunk(Box::new(GuildcardDataChunk::new(chunk, buf, len)))]
} else { } else {
@ -471,15 +474,17 @@ impl<EG: EntityGateway + Clone> CharacterServerState<EG> {
} }
async fn set_flag(&mut self, id: ClientId, setflag: &SetFlag) -> Result<std::option::IntoIter<SendCharacterPacket>, anyhow::Error> { 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 mut client = self.clients.write().await;
let client = client.get_mut(&id).ok_or_else(|| 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;
self.entity_gateway.save_user(user).await.unwrap(); self.entity_gateway.save_user(user).await.unwrap();
Ok(None.into_iter()) Ok(None.into_iter())
} }
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))?;
async fn param_data_chunk_request(&mut self, id: ClientId, _request: &ParamDataChunkRequest) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
let mut client = self.clients.write().await;
let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?;
let chunk = client.param_index; let chunk = client.param_index;
client.param_index += 1; client.param_index += 1;
@ -500,7 +505,8 @@ impl<EG: EntityGateway + Clone> 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>, anyhow::Error> { 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 mut client = self.clients.write().await;
let client = client.get_mut(&id).ok_or_else(|| 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 {
new_character(&mut self.entity_gateway, user, preview).await? new_character(&mut self.entity_gateway, user, preview).await?
@ -523,26 +529,30 @@ impl<EG: EntityGateway + Clone> CharacterServerState<EG> {
]) ])
} }
fn select_ship(&mut self, id: ClientId, menuselect: &MenuSelect) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
async fn select_ship(&mut self, id: ClientId, 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).into()); return Err(CharacterError::InvalidMenuSelection(menuselect.menu, menuselect.item).into());
} }
if let Some(client) = self.clients.get(&id) {
if let Some(client) = self.clients.read().await.get(&id) {
if let Some(user) = &client.user { if let Some(user) = &client.user {
if let Some(cc) = self.connected_clients.get_mut(&user.id) {
if let Some(cc) = self.connected_clients.write().await.get_mut(&user.id) {
cc.ship_id = Some(ServerId(menuselect.item as usize)); cc.ship_id = Some(ServerId(menuselect.item as usize));
} }
} }
} }
let ship = self.ships.get(&ServerId(menuselect.item as usize))
.ok_or(CharacterError::InvalidMenuSelection(menuselect.menu, menuselect.item))?;
let ship = self.ships.read().await;
let ship = ship.get(&ServerId(menuselect.item as usize))
.ok_or_else(|| CharacterError::InvalidMenuSelection(menuselect.menu, menuselect.item))?;
Ok(vec![SendCharacterPacket::RedirectClient(RedirectClient::new(u32::from_le_bytes(ship.ip.octets()), ship.port))]) Ok(vec![SendCharacterPacket::RedirectClient(RedirectClient::new(u32::from_le_bytes(ship.ip.octets()), ship.port))])
} }
fn ship_detail(&mut self, menudetail: &MenuDetail) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
let players = self.connected_clients.iter()
async fn ship_detail(&mut self, menudetail: &MenuDetail) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
let players = self.connected_clients
.read()
.await
.iter()
.filter(|(_, client)| { .filter(|(_, client)| {
client.ship_id == Some(ServerId(menudetail.item as usize)) client.ship_id == Some(ServerId(menudetail.item as usize))
}) })
@ -560,7 +570,7 @@ impl<EG: EntityGateway + Clone> ServerState for CharacterServerState<EG> {
type PacketError = anyhow::Error; type PacketError = anyhow::Error;
async fn on_connect(&mut self, id: ClientId) -> Result<Vec<OnConnect<Self::SendPacket, Self::Cipher>>, anyhow::Error> { async fn on_connect(&mut self, id: ClientId) -> Result<Vec<OnConnect<Self::SendPacket, Self::Cipher>>, anyhow::Error> {
self.clients.insert(id, ClientState::new());
self.clients.write().await.insert(id, ClientState::new());
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
@ -581,7 +591,7 @@ impl<EG: EntityGateway + Clone> ServerState for CharacterServerState<EG> {
Ok(match pkt { Ok(match pkt {
RecvCharacterPacket::Login(login) => { RecvCharacterPacket::Login(login) => {
if login.session.action == SessionAction::SelectCharacter { if login.session.action == SessionAction::SelectCharacter {
self.send_ship_list(id, &login)?.into_iter().map(move |pkt| (id, pkt)).collect()
self.send_ship_list(id, &login).await?.into_iter().map(move |pkt| (id, pkt)).collect()
} }
else { else {
self.validate_login(id, &login).await?.into_iter().map(move |pkt| (id, pkt)).collect() self.validate_login(id, &login).await?.into_iter().map(move |pkt| (id, pkt)).collect()
@ -600,7 +610,7 @@ impl<EG: EntityGateway + Clone> ServerState for CharacterServerState<EG> {
self.guildcard_data_header(id).await?.into_iter().map(move |pkt| (id, pkt)).collect() self.guildcard_data_header(id).await?.into_iter().map(move |pkt| (id, pkt)).collect()
}, },
RecvCharacterPacket::GuildcardDataChunkRequest(request) => { RecvCharacterPacket::GuildcardDataChunkRequest(request) => {
self.guildcard_data_chunk(id, request.chunk, request.again)?.into_iter().map(move |pkt| (id, pkt)).collect()
self.guildcard_data_chunk(id, request.chunk, request.again).await?.into_iter().map(move |pkt| (id, pkt)).collect()
}, },
RecvCharacterPacket::ParamDataRequest(_request) => { RecvCharacterPacket::ParamDataRequest(_request) => {
vec![SendCharacterPacket::ParamDataHeader(self.param_header.clone())].into_iter().map(move |pkt| (id, pkt)).collect() vec![SendCharacterPacket::ParamDataHeader(self.param_header.clone())].into_iter().map(move |pkt| (id, pkt)).collect()
@ -609,17 +619,17 @@ impl<EG: EntityGateway + Clone> ServerState for CharacterServerState<EG> {
self.set_flag(id, &flag).await?.map(move |pkt| (id, pkt)).collect() self.set_flag(id, &flag).await?.map(move |pkt| (id, pkt)).collect()
}, },
RecvCharacterPacket::ParamDataChunkRequest(request) => { RecvCharacterPacket::ParamDataChunkRequest(request) => {
self.param_data_chunk_request(id, &request)?.into_iter().map(move |pkt| (id, pkt)).collect()
self.param_data_chunk_request(id, &request).await?.into_iter().map(move |pkt| (id, pkt)).collect()
}, },
RecvCharacterPacket::CharacterPreview(preview) => { RecvCharacterPacket::CharacterPreview(preview) => {
self.character_preview(id, &preview).await?.into_iter().map(move |pkt| (id, pkt)).collect() self.character_preview(id, &preview).await?.into_iter().map(move |pkt| (id, pkt)).collect()
}, },
RecvCharacterPacket::MenuSelect(menuselect) => { RecvCharacterPacket::MenuSelect(menuselect) => {
self.select_ship(id, &menuselect)?.into_iter().map(move |pkt| (id, pkt)).collect()
self.select_ship(id, &menuselect).await?.into_iter().map(move |pkt| (id, pkt)).collect()
}, },
RecvCharacterPacket::MenuDetail(menudetail) => { RecvCharacterPacket::MenuDetail(menudetail) => {
match menudetail.menu { match menudetail.menu {
SHIP_MENU_ID => self.ship_detail(&menudetail)?.into_iter().map(move |pkt| (id, pkt)).collect(),
SHIP_MENU_ID => self.ship_detail(&menudetail).await?.into_iter().map(move |pkt| (id, pkt)).collect(),
_ => Vec::new() _ => Vec::new()
} }
} }
@ -627,9 +637,9 @@ impl<EG: EntityGateway + Clone> ServerState for CharacterServerState<EG> {
} }
async fn on_disconnect(&mut self, id: ClientId) -> Result<Vec<(ClientId, SendCharacterPacket)>, anyhow::Error> { 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.write().await.remove(&id) {
if let Some(user) = client.user { if let Some(user) = client.user {
self.connected_clients.remove(&user.id);
self.connected_clients.write().await.remove(&user.id);
} }
} }
Ok(Vec::new()) Ok(Vec::new())
@ -647,20 +657,25 @@ impl<EG: EntityGateway + Clone> InterserverActor for CharacterServerState<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::RecvMessage) -> Result<Vec<(ServerId, Self::SendMessage)>, Self::Error> {
dbg!(&id, &msg);
match msg { match msg {
ShipMessage::Authenticate(auth_token) => { ShipMessage::Authenticate(auth_token) => {
if self.auth_token == auth_token { if self.auth_token == auth_token {
self.authenticated_ships.insert(id);
self.authenticated_ships.write().await.insert(id);
} }
Ok(Vec::new()) Ok(Vec::new())
}, },
ShipMessage::NewShip(new_ship) => { ShipMessage::NewShip(new_ship) => {
if self.authenticated_ships.contains(&id) {
self.ships.insert(id, new_ship);
dbg!("adding ship", &id, &new_ship);
if self.authenticated_ships.read().await.contains(&id) {
self.ships.write().await.insert(id, new_ship);
} }
dbg!("ship list", &self.authenticated_ships);
let ships = self.ships.iter().map(|(_, s)| s).cloned().collect::<Vec<_>>();
let ships = self.ships.read().await.iter().map(|(_, s)| s).cloned().collect::<Vec<_>>();
Ok(self.ships Ok(self.ships
.read()
.await
.iter() .iter()
.map(|(id, _)| { .map(|(id, _)| {
(*id, LoginMessage::ShipList{ ships: ships.clone() }) (*id, LoginMessage::ShipList{ ships: ships.clone() })
@ -668,8 +683,8 @@ impl<EG: EntityGateway + Clone> InterserverActor for CharacterServerState<EG> {
.collect()) .collect())
}, },
ShipMessage::AddUser(new_user) => { ShipMessage::AddUser(new_user) => {
if self.authenticated_ships.contains(&id) {
self.connected_clients.insert(new_user, ConnectedClient {
if self.authenticated_ships.read().await.contains(&id) {
self.connected_clients.write().await.insert(new_user, ConnectedClient {
ship_id: Some(id), ship_id: Some(id),
expires: None, expires: None,
}); });
@ -677,15 +692,18 @@ impl<EG: EntityGateway + Clone> InterserverActor for CharacterServerState<EG> {
Ok(Vec::new()) Ok(Vec::new())
}, },
ShipMessage::RemoveUser(new_user) => { ShipMessage::RemoveUser(new_user) => {
if self.authenticated_ships.contains(&id) {
self.connected_clients.remove(&new_user);
if self.authenticated_ships.read().await.contains(&id) {
self.connected_clients.write().await.remove(&new_user);
} }
Ok(Vec::new()) Ok(Vec::new())
}, },
ShipMessage::RequestShipList => { ShipMessage::RequestShipList => {
if self.authenticated_ships.contains(&id) {
dbg!("request ship list", &self.authenticated_ships);
if self.authenticated_ships.read().await.contains(&id) {
Ok(vec![(id, LoginMessage::ShipList { Ok(vec![(id, LoginMessage::ShipList {
ships: self.ships ships: self.ships
.read()
.await
.iter() .iter()
.map(|(_, ship)| { .map(|(_, ship)| {
ship ship
@ -705,18 +723,19 @@ impl<EG: EntityGateway + Clone> InterserverActor for CharacterServerState<EG> {
} }
async fn on_disconnect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> { async fn on_disconnect(&mut self, id: ServerId) -> Vec<(ServerId, Self::SendMessage)> {
self.ships.remove(&id);
self.ship_sender.remove(&id);
self.connected_clients = self.connected_clients.clone().into_iter()
.filter(|(_, client)| {
self.ships.write().await.remove(&id);
self.ship_sender.write().await.remove(&id);
self.connected_clients
.write()
.await
.retain(|_, client| {
client.ship_id != Some(id) client.ship_id != Some(id)
})
.collect();
});
Vec::new() Vec::new()
} }
fn set_sender(&mut self, server_id: ServerId, sender: channel::Sender<LoginMessage>) {
self.ship_sender.insert(server_id, sender);
async fn set_sender(&mut self, server_id: ServerId, sender: channel::Sender<LoginMessage>) {
self.ship_sender.write().await.insert(server_id, sender);
} }
} }
@ -845,7 +864,7 @@ mod test {
at_character: false, at_character: false,
at_ship: false, at_ship: false,
}); });
server.clients.insert(ClientId(5), clientstate);
server.clients.write().await.insert(ClientId(5), clientstate);
let send = server.handle(ClientId(5), RecvCharacterPacket::RequestSettings(RequestSettings{})).await.unwrap(); let send = server.handle(ClientId(5), RecvCharacterPacket::RequestSettings(RequestSettings{})).await.unwrap();
assert!(send.len() == 1); assert!(send.len() == 1);
@ -892,7 +911,7 @@ mod test {
}); });
let mut server = CharacterServerState::new(test_data.clone(), AuthToken("".into())); let mut server = CharacterServerState::new(test_data.clone(), AuthToken("".into()));
server.clients.insert(ClientId(1), fake_user.clone());
server.clients.write().await.insert(ClientId(1), fake_user.clone());
let mut send = server.handle(ClientId(1), RecvCharacterPacket::SetFlag(SetFlag {flags: 1})).await.unwrap(); let mut send = server.handle(ClientId(1), RecvCharacterPacket::SetFlag(SetFlag {flags: 1})).await.unwrap();
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);
send = server.handle(ClientId(1), RecvCharacterPacket::CharacterPreview(CharacterPreview {slot: 1, character: character::SelectScreenCharacter { send = server.handle(ClientId(1), RecvCharacterPacket::CharacterPreview(CharacterPreview {slot: 1, character: character::SelectScreenCharacter {

3
src/patch/patch.rs

@ -190,9 +190,8 @@ impl ServerState for PatchServerState {
.collect() .collect()
}, },
RecvPatchPacket::FileInfoReply(pkt) => { RecvPatchPacket::FileInfoReply(pkt) => {
self.patch_file_info.push(pkt.clone());
self.patch_file_info.push(pkt);
Vec::new() Vec::new()
//None.into_iter().map(move |pkt| (id, pkt))
}, },
RecvPatchPacket::FileInfoListEnd(_pkt) => { RecvPatchPacket::FileInfoListEnd(_pkt) => {
let need_update = self.patch_file_info.iter() let need_update = self.patch_file_info.iter()

2
src/ship/character.rs

@ -77,7 +77,7 @@ impl<'a> CharacterBytesBuilder<'a> {
prop_y: character.appearance.prop_y, prop_y: character.appearance.prop_y,
config: character.config.as_bytes(), config: character.config.as_bytes(),
techniques: character.techs.as_bytes(), techniques: character.techs.as_bytes(),
meseta: meseta.0 as u32,
meseta: meseta.0,
exp: character.exp, exp: character.exp,
..character::Character::default() ..character::Character::default()
} }

14
src/ship/items/actions.rs

@ -30,7 +30,7 @@ pub(super) fn take_item_from_floor(character_id: CharacterEntityId, item_id: Cli
move |(mut item_state, transaction): (ItemStateProxy<'_>, Box<dyn EntityGatewayTransaction + '_>) , _| { move |(mut item_state, transaction): (ItemStateProxy<'_>, Box<dyn EntityGatewayTransaction + '_>) , _| {
Box::pin(async move { Box::pin(async move {
let mut floor = item_state.floor(&character_id).await?; let mut floor = item_state.floor(&character_id).await?;
let item = floor.take_item(&item_id).ok_or(ItemStateError::NoFloorItem(item_id))?;
let item = floor.take_item(&item_id).ok_or_else(|| ItemStateError::NoFloorItem(item_id))?;
item_state.set_floor(floor).await; item_state.set_floor(floor).await;
Ok(((item_state, transaction), item)) Ok(((item_state, transaction), item))
@ -88,7 +88,7 @@ pub(super) fn take_item_from_inventory(character_id: CharacterEntityId, item_id:
move |(mut item_state, mut transaction), _| { move |(mut item_state, mut transaction), _| {
Box::pin(async move { Box::pin(async move {
let mut inventory = item_state.inventory(&character_id).await?; let mut inventory = item_state.inventory(&character_id).await?;
let item = inventory.take_item(&item_id, amount).ok_or (ItemStateError::NoFloorItem(item_id))?;
let item = inventory.take_item(&item_id, amount).ok_or_else(|| ItemStateError::NoFloorItem(item_id))?;
transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?; transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?;
item_state.set_inventory(inventory); item_state.set_inventory(inventory);
@ -238,7 +238,7 @@ pub(super) fn take_item_from_bank(character_id: CharacterEntityId, item_id: Clie
move |(mut item_state, mut transaction), _| { move |(mut item_state, mut transaction), _| {
Box::pin(async move { Box::pin(async move {
let mut bank = item_state.bank(&character_id).await?; let mut bank = item_state.bank(&character_id).await?;
let item = bank.take_item(&item_id, amount).ok_or(ItemStateError::NoBankItem(item_id))?;
let item = bank.take_item(&item_id, amount).ok_or_else(|| ItemStateError::NoBankItem(item_id))?;
transaction.gateway().set_character_bank(&character_id, &bank.as_bank_entity(), &bank.name).await?; transaction.gateway().set_character_bank(&character_id, &bank.as_bank_entity(), &bank.name).await?;
item_state.set_bank(bank); item_state.set_bank(bank);
@ -407,10 +407,10 @@ pub(super) fn feed_mag_item(character: CharacterEntity, mag_item_id: ClientItemI
Box::pin(async move { Box::pin(async move {
let mut inventory = item_state.inventory(&character.id).await?; let mut inventory = item_state.inventory(&character.id).await?;
let mag_entity = inventory.get_by_client_id_mut(&mag_item_id) let mag_entity = inventory.get_by_client_id_mut(&mag_item_id)
.ok_or(ItemStateError::InvalidItemId(mag_item_id))?
.ok_or_else(|| ItemStateError::InvalidItemId(mag_item_id))?
.item .item
.as_individual_mut() .as_individual_mut()
.ok_or(ItemStateError::NotAMag(mag_item_id))?;
.ok_or_else(|| ItemStateError::NotAMag(mag_item_id))?;
let mag_entity_id = mag_entity.entity_id; let mag_entity_id = mag_entity.entity_id;
let mut transaction = tool.with_entity_id(transaction, |mut transaction, entity_id| { let mut transaction = tool.with_entity_id(transaction, |mut transaction, entity_id| {
@ -426,13 +426,13 @@ pub(super) fn feed_mag_item(character: CharacterEntity, mag_item_id: ClientItemI
let food_tool = tool let food_tool = tool
.item .item
.stacked() .stacked()
.ok_or(ItemStateError::NotMagFood(tool.item_id))?
.ok_or_else(|| ItemStateError::NotMagFood(tool.item_id))?
.tool .tool
.tool; .tool;
let mag_entity = mag_entity let mag_entity = mag_entity
.as_mag_mut() .as_mag_mut()
.ok_or(ItemStateError::NotAMag(mag_item_id))?;
.ok_or_else(|| ItemStateError::NotAMag(mag_item_id))?;
mag_entity.feed(food_tool); mag_entity.feed(food_tool);

96
src/ship/items/state.rs

@ -1,23 +1,19 @@
use std::collections::HashMap; use std::collections::HashMap;
use async_std::sync::{Arc, RwLock}; use async_std::sync::{Arc, RwLock};
use crate::ship::items::ClientItemId;
use crate::entity::item::{ItemEntityId, ItemDetail, ItemEntity, InventoryItemEntity, BankItemEntity, BankName};
use futures::future::join_all; use futures::future::join_all;
use crate::ship::location::{AreaClient, RoomId};
use crate::entity::character::{CharacterEntity, CharacterEntityId};
use crate::entity::gateway::{EntityGateway, GatewayError}; use crate::entity::gateway::{EntityGateway, GatewayError};
use crate::entity::character::{CharacterEntity, CharacterEntityId};
use crate::entity::item::{ItemEntityId, ItemDetail, ItemEntity, InventoryItemEntity, BankItemEntity, BankName};
use crate::entity::item::tool::Tool; use crate::entity::item::tool::Tool;
use crate::entity::item::weapon::Weapon; use crate::entity::item::weapon::Weapon;
use crate::entity::item::mag::Mag; use crate::entity::item::mag::Mag;
use crate::ship::drops::ItemDrop; use crate::ship::drops::ItemDrop;
use crate::ship::items::ClientItemId;
use crate::ship::items::inventory::{Inventory, InventoryItem, InventoryItemDetail, InventoryError, InventoryState}; use crate::ship::items::inventory::{Inventory, InventoryItem, InventoryItemDetail, InventoryError, InventoryState};
use crate::ship::items::floor::{FloorState, FloorItem, LocalFloor, SharedFloor, FloorType}; use crate::ship::items::floor::{FloorState, FloorItem, LocalFloor, SharedFloor, FloorType};
use crate::ship::items::bank::{Bank, BankState, BankItem, BankItemDetail, BankError}; use crate::ship::items::bank::{Bank, BankState, BankItem, BankItemDetail, BankError};
use crate::ship::location::{AreaClient, RoomId};
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum ItemStateError { pub enum ItemStateError {
@ -27,55 +23,38 @@ pub enum ItemStateError {
NoRoom(RoomId), NoRoom(RoomId),
#[error("floor item {0} not found")] #[error("floor item {0} not found")]
NoFloorItem(ClientItemId), NoFloorItem(ClientItemId),
#[error("expected {0} to be a tool")] #[error("expected {0} to be a tool")]
NotATool(ClientItemId), NotATool(ClientItemId),
#[error("bank item {0} not found")] #[error("bank item {0} not found")]
NoBankItem(ClientItemId), NoBankItem(ClientItemId),
#[error("inventory error {0}")] #[error("inventory error {0}")]
InventoryError(#[from] InventoryError), InventoryError(#[from] InventoryError),
#[error("bank error {0}")] #[error("bank error {0}")]
BankError(#[from] BankError), BankError(#[from] BankError),
#[error("invalid item id {0}")] #[error("invalid item id {0}")]
InvalidItemId(ClientItemId), InvalidItemId(ClientItemId),
#[error("invalid drop? {0:?} (this shouldn't occur)")] #[error("invalid drop? {0:?} (this shouldn't occur)")]
BadItemDrop(ItemDrop), BadItemDrop(ItemDrop),
#[error("idk")] #[error("idk")]
Dummy, Dummy,
#[error("gateway")] #[error("gateway")]
GatewayError(#[from] GatewayError), GatewayError(#[from] GatewayError),
#[error("tried to remove more meseta than exists: {0}")] #[error("tried to remove more meseta than exists: {0}")]
InvalidMesetaRemoval(u32), InvalidMesetaRemoval(u32),
#[error("tried to add meseta when there is no more room")] #[error("tried to add meseta when there is no more room")]
FullOfMeseta, FullOfMeseta,
#[error("stacked item")] #[error("stacked item")]
StackedItemError(Vec<ItemEntity>), StackedItemError(Vec<ItemEntity>),
#[error("apply item {0}")] #[error("apply item {0}")]
ApplyItemError(#[from] crate::ship::items::apply_item::ApplyItemError), ApplyItemError(#[from] crate::ship::items::apply_item::ApplyItemError),
#[error("item is not a mag {0}")] #[error("item is not a mag {0}")]
NotAMag(ClientItemId), NotAMag(ClientItemId),
#[error("item is not mag food {0}")] #[error("item is not mag food {0}")]
NotMagFood(ClientItemId), NotMagFood(ClientItemId),
#[error("item is not sellable")] #[error("item is not sellable")]
ItemNotSellable, ItemNotSellable,
#[error("could not modify item")] #[error("could not modify item")]
InvalidModifier, InvalidModifier,
#[error("wrong item type ")] #[error("wrong item type ")]
WrongItemType(ClientItemId), WrongItemType(ClientItemId),
} }
@ -137,7 +116,6 @@ impl StackedItemDetail {
} }
#[derive(Clone)] #[derive(Clone)]
pub enum AddItemResult { pub enum AddItemResult {
NewItem, NewItem,
@ -177,7 +155,7 @@ impl ItemState {
.read() .read()
.await .await
.get(&character.id) .get(&character.id)
.ok_or(ItemStateError::NoCharacter(character.id))?
.ok_or_else(|| ItemStateError::NoCharacter(character.id))?
.read() .read()
.await .await
.clone()) .clone())
@ -188,7 +166,7 @@ impl ItemState {
.read() .read()
.await .await
.get(&character.id) .get(&character.id)
.ok_or(ItemStateError::NoCharacter(character.id))?
.ok_or_else(|| ItemStateError::NoCharacter(character.id))?
.read() .read()
.await .await
.clone()) .clone())
@ -197,7 +175,6 @@ impl ItemState {
impl ItemState { impl ItemState {
async fn new_item_id(&mut self) -> Result<ClientItemId, ItemStateError> { async fn new_item_id(&mut self) -> Result<ClientItemId, ItemStateError> {
//self.room_item_id_counter += 1;
*self.room_item_id_counter *self.room_item_id_counter
.write() .write()
.await += 1; .await += 1;
@ -300,7 +277,6 @@ impl ItemState {
pub async fn add_character_to_room(&mut self, room_id: RoomId, character: &CharacterEntity, area_client: AreaClient) { pub async fn add_character_to_room(&mut self, room_id: RoomId, character: &CharacterEntity, area_client: AreaClient) {
let base_inventory_id = ((area_client.local_client.id() as u32) << 21) | 0x10000; let base_inventory_id = ((area_client.local_client.id() as u32) << 21) | 0x10000;
//let inventory = self.character_inventory.get_mut(&character.id).unwrap();
self.character_inventory self.character_inventory
.read() .read()
.await .await
@ -309,9 +285,7 @@ impl ItemState {
.write() .write()
.await .await
.initialize_item_ids(base_inventory_id); .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);
self.character_bank self.character_bank
.read() .read()
.await .await
@ -320,9 +294,6 @@ impl ItemState {
.write() .write()
.await .await
.initialize_item_ids(base_bank_id); .initialize_item_ids(base_bank_id);
//if let Some(default_bank) = default_bank {
//default_bank.initialize_item_ids(base_bank_id);
//}
self.character_room self.character_room
.write() .write()
.await .await
@ -369,7 +340,7 @@ impl ItemState {
.await; .await;
let local_floor = local_floors let local_floor = local_floors
.get(character_id) .get(character_id)
.ok_or(ItemStateError::NoCharacter(*character_id))?
.ok_or_else(|| ItemStateError::NoCharacter(*character_id))?
.read() .read()
.await; .await;
let rooms = self.character_room let rooms = self.character_room
@ -377,13 +348,13 @@ impl ItemState {
.await; .await;
let room = rooms let room = rooms
.get(character_id) .get(character_id)
.ok_or(ItemStateError::NoCharacter(*character_id))?;
.ok_or_else(||ItemStateError::NoCharacter(*character_id))?;
let shared_floors = self.room_floor let shared_floors = self.room_floor
.read() .read()
.await; .await;
let shared_floor = shared_floors let shared_floor = shared_floors
.get(room) .get(room)
.ok_or(ItemStateError::NoCharacter(*character_id))?
.ok_or_else(||ItemStateError::NoCharacter(*character_id))?
.read() .read()
.await; .await;
@ -397,7 +368,7 @@ impl ItemState {
.find(|item| item.item_id == *item_id) .find(|item| item.item_id == *item_id)
.map(|item| (item.clone(), FloorType::Shared)) .map(|item| (item.clone(), FloorType::Shared))
}) })
.ok_or(ItemStateError::NoFloorItem(*item_id))
.ok_or_else(|| ItemStateError::NoFloorItem(*item_id))
} }
} }
@ -415,12 +386,10 @@ struct ProxiedItemState {
pub struct ItemStateProxy<'a> { pub struct ItemStateProxy<'a> {
item_state: &'a mut ItemState, item_state: &'a mut ItemState,
proxied_state: ProxiedItemState, proxied_state: ProxiedItemState,
//_a: std::marker::PhantomData<&'a ()>, // TODO: remove
} }
impl<'a> ItemStateProxy<'a> { impl<'a> ItemStateProxy<'a> {
pub async fn commit(self) { pub async fn commit(self) {
async fn copy_back<K, V>(master: &Arc<RwLock<HashMap<K, RwLock<V>>>>, async fn copy_back<K, V>(master: &Arc<RwLock<HashMap<K, RwLock<V>>>>,
proxy: HashMap<K, V>) proxy: HashMap<K, V>)
where where
@ -443,43 +412,6 @@ impl<'a> ItemStateProxy<'a> {
//copy_back(self.item_state.character_room, self.proxied_state.character_room).await; //copy_back(self.item_state.character_room, self.proxied_state.character_room).await;
copy_back(&self.item_state.character_floor, self.proxied_state.character_floor).await; copy_back(&self.item_state.character_floor, self.proxied_state.character_floor).await;
copy_back(&self.item_state.room_floor, self.proxied_state.room_floor).await; copy_back(&self.item_state.room_floor, self.proxied_state.room_floor).await;
/*
self.item_state.character_inventory
.write()
.await
.extend(self.proxied_state.character_inventory.clone());
self.item_state.character_bank
.write()
.await
.extend(self.proxied_state.character_bank.clone());
self.item_state.character_room
.write()
.await
.extend(self.proxied_state.character_room.clone());
self.item_state.character_floor
.write()
.await
.extend(self.proxied_state.character_floor.clone());
self.item_state.room_floor
.write()
.await
.extend(self.proxied_state.room_floor);
*/
/*
for (character_id, character_inventory) in self.proxied_state.character_inventory {
if let Some(inventory) = self.item_state.character_inventory
.read()
.await
.get(&character_id) {
*inventory
.write()
.await = character_inventory;
}
}
*/
} }
} }
@ -492,11 +424,6 @@ where
K: Eq + std::hash::Hash + Copy, K: Eq + std::hash::Hash + Copy,
V: Clone V: Clone
{ {
/*
let existing_element = master.get(&key).ok_or_else(|| err(key))?;
Ok(proxy.entry(key)
.or_insert_with(|| existing_element.clone()).clone())
*/
let existing_element = master let existing_element = master
.read() .read()
.await .await
@ -516,7 +443,6 @@ impl<'a> ItemStateProxy<'a> {
ItemStateProxy { ItemStateProxy {
item_state, item_state,
proxied_state: Default::default(), proxied_state: Default::default(),
//_a: Default::default(),
} }
} }
@ -543,7 +469,6 @@ impl<'a> ItemStateProxy<'a> {
} }
pub async fn floor(&mut self, character_id: &CharacterEntityId) -> Result<FloorState, ItemStateError> { pub async fn floor(&mut self, character_id: &CharacterEntityId) -> Result<FloorState, ItemStateError> {
//let room_id = get_or_clone(&self.item_state.character_room, &mut self.proxied_state.character_room, *character_id, ItemStateError::NoCharacter)?;
let room_id = *self.item_state.character_room.read().await.get(character_id).unwrap(); let room_id = *self.item_state.character_room.read().await.get(character_id).unwrap();
Ok(FloorState { Ok(FloorState {
character_id: *character_id, character_id: *character_id,
@ -553,7 +478,6 @@ impl<'a> ItemStateProxy<'a> {
} }
pub async fn set_floor(&mut self, floor: FloorState) { pub async fn set_floor(&mut self, floor: FloorState) {
//let room_id = get_or_clone(&self.item_state.character_room, &mut self.proxied_state.character_room, floor.character_id, ItemStateError::NoCharacter).unwrap();
let room_id = *self.item_state.character_room.read().await.get(&floor.character_id).unwrap(); let room_id = *self.item_state.character_room.read().await.get(&floor.character_id).unwrap();
self.proxied_state.character_floor.insert(floor.character_id, floor.local); self.proxied_state.character_floor.insert(floor.character_id, floor.local);
self.proxied_state.room_floor.insert(room_id, floor.shared); self.proxied_state.room_floor.insert(room_id, floor.shared);

2
src/ship/map/area.rs

@ -320,7 +320,7 @@ pub struct MapAreaLookup(HashMap<u16, MapArea>);
impl MapAreaLookup { impl MapAreaLookup {
pub fn get_area_map(&self, map_area: u16) -> Result<MapArea, MapAreaError> { pub fn get_area_map(&self, map_area: u16) -> Result<MapArea, MapAreaError> {
self.0.get(&map_area) self.0.get(&map_area)
.map(|a| *a)
.copied()
.ok_or(MapAreaError::UnknownMapArea(map_area)) .ok_or(MapAreaError::UnknownMapArea(map_area))
} }

2
src/ship/packet/builder/lobby.rs

@ -43,7 +43,7 @@ pub async fn join_lobby(id: ClientId,
block: client_block, block: client_block,
event: 0, event: 0,
padding: 0, padding: 0,
playerinfo: playerinfo,
playerinfo,
}) })
} }

11
src/ship/packet/handler/auth.rs

@ -23,20 +23,21 @@ where
Ok(match get_login_status(entity_gateway, &pkt).await { Ok(match get_login_status(entity_gateway, &pkt).await {
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 as u32;
response.team_id = user.team_id.map_or(31, |ti| ti) as u32;
response.guildcard = user.id.0;
response.team_id = user.team_id.map_or(31, |ti| ti);
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)
.ok_or(ShipError::InvalidSlot(id, pkt.session.character_slot as u32))?.as_ref()
.ok_or(ShipError::NoCharacterInSlot(id, pkt.session.character_slot as u32))?
.ok_or_else(|| ShipError::InvalidSlot(id, pkt.session.character_slot as u32))?
.as_ref()
.ok_or_else(|| ShipError::NoCharacterInSlot(id, pkt.session.character_slot as u32))?
.clone(); .clone();
let settings = entity_gateway.get_user_settings_by_user(&user).await?; let settings = entity_gateway.get_user_settings_by_user(&user).await?;
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.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;
vec![SendShipPacket::LoginResponse(response), SendShipPacket::ShipBlockList(ShipBlockList::new(ship_name, num_blocks))] vec![SendShipPacket::LoginResponse(response), SendShipPacket::ShipBlockList(ShipBlockList::new(ship_name, num_blocks))]

2
src/ship/packet/handler/communication.rs

@ -17,7 +17,7 @@ pub async fn player_chat(id: ClientId,
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()
.map(move |client| { .map(move |client| {
(client.client, SendShipPacket::PlayerChat(cmsg.clone()).clone())
(client.client, SendShipPacket::PlayerChat(cmsg.clone()))
}) })
.collect()) .collect())
} }

42
src/ship/packet/handler/direct_message.rs

@ -6,7 +6,7 @@ use libpso::packet::messages::*;
use crate::common::leveltable::LEVEL_TABLE; use crate::common::leveltable::LEVEL_TABLE;
use crate::common::serverstate::ClientId; use crate::common::serverstate::ClientId;
use crate::ship::ship::{SendShipPacket, ShipError, Clients, ItemShops}; use crate::ship::ship::{SendShipPacket, ShipError, Clients, ItemShops};
use crate::ship::location::{ClientLocation, ClientLocationError};
use crate::ship::location::ClientLocation;
use crate::ship::drops::ItemDrop; use crate::ship::drops::ItemDrop;
use crate::ship::room::Rooms; use crate::ship::room::Rooms;
use crate::ship::items::ClientItemId; use crate::ship::items::ClientItemId;
@ -86,16 +86,16 @@ pub async fn request_item<EG>(id: ClientId,
where where
EG: EntityGateway EG: EntityGateway
{ {
let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let room_id = client_location.get_room(id).await?;
let monster = rooms.with(room_id, |room| Box::pin(async move { let monster = rooms.with(room_id, |room| Box::pin(async move {
room.maps.enemy_by_id(request_item.enemy_id as usize) room.maps.enemy_by_id(request_item.enemy_id as usize)
})).await??; })).await??;
if monster.dropped_item { if monster.dropped_item {
return Err(ShipError::MonsterAlreadyDroppedItem(id, request_item.enemy_id).into())
return Err(ShipError::MonsterAlreadyDroppedItem(id, request_item.enemy_id))
} }
let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let clients_in_area = client_location.get_clients_in_room(room_id).await?;
let client_and_drop = rooms.with_mut(room_id, |room| Box::pin(async move { let client_and_drop = rooms.with_mut(room_id, |room| Box::pin(async move {
clients_in_area.into_iter() clients_in_area.into_iter()
.filter_map(move |area_client| { .filter_map(move |area_client| {
@ -138,9 +138,9 @@ pub async fn pickup_item<EG>(id: ClientId,
where where
EG: EntityGateway + Clone + 'static, EG: EntityGateway + Clone + 'static,
{ {
let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let area_client = client_location.get_local_client(id).await?;
let room_id = client_location.get_room(id).await?;
let clients_in_area = client_location.get_clients_in_room(room_id).await?;
clients.with(id, |client| { clients.with(id, |client| {
let mut entity_gateway = entity_gateway.clone(); let mut entity_gateway = entity_gateway.clone();
@ -197,16 +197,16 @@ pub async fn request_box_item<EG>(id: ClientId,
where where
EG: EntityGateway + Clone + 'static EG: EntityGateway + Clone + 'static
{ {
let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let room_id = client_location.get_room(id).await?;
let box_object = rooms.with(room_id, |room| Box::pin(async move { let box_object = rooms.with(room_id, |room| Box::pin(async move {
room.maps.object_by_id(box_drop_request.object_id as usize) room.maps.object_by_id(box_drop_request.object_id as usize)
})).await??; })).await??;
if box_object.dropped_item { if box_object.dropped_item {
return Err(ShipError::BoxAlreadyDroppedItem(id, box_drop_request.object_id).into())
return Err(ShipError::BoxAlreadyDroppedItem(id, box_drop_request.object_id))
} }
let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let clients_in_area = client_location.get_clients_in_room(room_id).await?;
let client_and_drop = rooms.with_mut(room_id, |room| Box::pin(async move { let client_and_drop = rooms.with_mut(room_id, |room| Box::pin(async move {
clients_in_area.into_iter() clients_in_area.into_iter()
@ -266,8 +266,8 @@ pub async fn bank_interaction<EG>(id: ClientId,
where where
EG: EntityGateway + Clone + 'static, EG: EntityGateway + Clone + 'static,
{ {
let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let other_clients_in_area = client_location.get_all_clients_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let area_client = client_location.get_local_client(id).await?;
let other_clients_in_area = client_location.get_all_clients_by_client(id).await?;
let bank_action_pkts = clients.with(id, |client| { let bank_action_pkts = clients.with(id, |client| {
let mut entity_gateway = entity_gateway.clone(); let mut entity_gateway = entity_gateway.clone();
@ -323,7 +323,7 @@ pub async fn shop_request(id: ClientId,
-> Result<Vec<(ClientId, SendShipPacket)>, ShipError> -> Result<Vec<(ClientId, SendShipPacket)>, ShipError>
{ {
//let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; //let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let room_id = client_location.get_room(id).await?;
/* /*
let room = rooms.get(room_id.0) let room = rooms.get(room_id.0)
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))? .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?
@ -401,7 +401,7 @@ pub async fn buy_item<EG>(id: ClientId,
where where
EG: EntityGateway + Clone + 'static, EG: EntityGateway + Clone + 'static,
{ {
let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let area_client = client_location.get_local_client(id).await?;
let create = clients.with_mut(id, |client| { let create = clients.with_mut(id, |client| {
let mut entity_gateway = entity_gateway.clone(); let mut entity_gateway = entity_gateway.clone();
@ -422,7 +422,7 @@ where
(item, remove) (item, remove)
}, },
_ => { _ => {
return Err(ShipError::ShopError.into())
return Err(ShipError::ShopError)
} }
}; };
@ -442,7 +442,7 @@ where
builder::message::create_withdrawn_inventory_item(area_client, &inventory_item) builder::message::create_withdrawn_inventory_item(area_client, &inventory_item)
})}).await??; })}).await??;
let other_clients_in_area = client_location.get_client_neighbors(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let other_clients_in_area = client_location.get_client_neighbors(id).await?;
Ok(other_clients_in_area.into_iter() Ok(other_clients_in_area.into_iter()
.map(move |c| { .map(move |c| {
(c.client, SendShipPacket::Message(Message::new(GameMessage::CreateItem(create.clone())))) (c.client, SendShipPacket::Message(Message::new(GameMessage::CreateItem(create.clone()))))
@ -489,11 +489,11 @@ where
let inventory = item_state.get_character_inventory(&client.character).await?; let inventory = item_state.get_character_inventory(&client.character).await?;
let item = inventory.get_by_client_id(&ClientItemId(tek_request.item_id)) let item = inventory.get_by_client_id(&ClientItemId(tek_request.item_id))
.ok_or(ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))?;
.ok_or_else(|| ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))?;
let mut weapon = *item.item.as_individual() let mut weapon = *item.item.as_individual()
.ok_or(ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))?
.ok_or_else(|| ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))?
.as_weapon() .as_weapon()
.ok_or(ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))?;
.ok_or_else(|| ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))?;
weapon.apply_modifier(&item::weapon::WeaponModifier::Tekked { weapon.apply_modifier(&item::weapon::WeaponModifier::Tekked {
special: special_mod, special: special_mod,
@ -519,8 +519,8 @@ pub async fn accept_tek_item<EG>(id: ClientId,
where where
EG: EntityGateway + Clone + 'static, EG: EntityGateway + Clone + 'static,
{ {
let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let neighbors = client_location.get_client_neighbors(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let area_client = client_location.get_local_client(id).await?;
let neighbors = client_location.get_client_neighbors(id).await?;
clients.with(id, |client| { clients.with(id, |client| {
let mut entity_gateway = entity_gateway.clone(); let mut entity_gateway = entity_gateway.clone();

32
src/ship/packet/handler/lobby.rs

@ -146,45 +146,17 @@ pub async fn remove_from_lobby(id: ClientId,
pub async fn get_room_tab_info(id: ClientId, pub async fn get_room_tab_info(id: ClientId,
pkt: MenuDetail, pkt: MenuDetail,
client_location: &mut ClientLocation, client_location: &mut ClientLocation,
clients: &Clients,
rooms: &mut Rooms)
clients: &Clients)
-> Result<Vec<(ClientId, SendShipPacket)>, ShipError> { -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> {
/*
let room_id = RoomId(pkt.item as usize); let room_id = RoomId(pkt.item as usize);
if let Some(_room) = rooms.get(pkt.item as usize).ok_or(ShipError::InvalidRoom(pkt.item))? {
let mut room_info = String::new();
let clients_in_room = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?;
for client in clients_in_room {
let cs = clients.get(&client.client).ok_or(ShipError::ClientNotFound(client.client))?;
let gc = cs.user.guildcard;
let name = &cs.character.name;
let cc = cs.character.char_class;
let lv = LEVEL_TABLE.get_level_from_exp(cc, cs.character.exp);
let floor = cs.area.unwrap_or(MapArea::Pioneer2Ep1);
room_info += format!("{} Lv{} {}\n{} {}\n", gc,lv,name,cc,floor).as_str();
}
Ok(vec![(id, SendShipPacket::SmallLeftDialog(SmallLeftDialog::new(room_info)))])
} else {
Ok(vec![(id, SendShipPacket::SmallLeftDialog(SmallLeftDialog::new("Game is no longer active".into())))])
}
*/
dbg!("a");
let room_id = RoomId(pkt.item as usize);
dbg!("b");
let clients_in_room = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; let clients_in_room = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?;
dbg!("c");
let room_info = if clients_in_room.len() == 0 {
dbg!("d");
let room_info = if clients_in_room.is_empty() {
String::from("Game is no longer active") String::from("Game is no longer active")
} }
else { else {
dbg!("d2");
join_all(clients_in_room.iter() join_all(clients_in_room.iter()
.map(|clientl| async move { .map(|clientl| async move {
dbg!("e");
clients.with(clientl.client, |client| Box::pin(async move { clients.with(clientl.client, |client| Box::pin(async move {
dbg!("f");
format!("{} Lv{} {}\n{} {}", format!("{} Lv{} {}\n{} {}",
client.character.name, client.character.name,
LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp), LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp),

10
src/ship/packet/handler/message.rs

@ -28,7 +28,7 @@ where
let enemy_id = request_exp.enemy_id as usize; let enemy_id = request_exp.enemy_id as usize;
let enemy_exp = rooms.with(room_id, |room| Box::pin(async move { let enemy_exp = rooms.with(room_id, |room| Box::pin(async move {
let monster = room.maps.enemy_by_id(enemy_id)?; let monster = room.maps.enemy_by_id(enemy_id)?;
let monster_stats = room.monster_stats.get(&monster.monster).ok_or(ShipError::UnknownMonster(monster.monster))?;
let monster_stats = room.monster_stats.get(&monster.monster).ok_or_else(|| ShipError::UnknownMonster(monster.monster))?;
Ok::<_, ShipError>(monster_stats.exp) Ok::<_, ShipError>(monster_stats.exp)
})).await??; })).await??;
@ -150,7 +150,7 @@ where
})).await?; })).await?;
if let Some(drop_location) = drop_location { if let Some(drop_location) = drop_location {
if drop_location.item_id.0 != no_longer_has_item.item_id { if drop_location.item_id.0 != no_longer_has_item.item_id {
return Err(ShipError::DropInvalidItemId(no_longer_has_item.item_id).into());
return Err(ShipError::DropInvalidItemId(no_longer_has_item.item_id));
} }
if no_longer_has_item.item_id == 0xFFFFFFFF { if no_longer_has_item.item_id == 0xFFFFFFFF {
@ -163,7 +163,7 @@ where
})}).await??; })}).await??;
let dropped_meseta_pkt = builder::message::drop_split_meseta_stack(area_client, &dropped_meseta)?; let dropped_meseta_pkt = builder::message::drop_split_meseta_stack(area_client, &dropped_meseta)?;
let no_longer_has_meseta_pkt = builder::message::player_no_longer_has_meseta(area_client, no_longer_has_item.amount as u32);
let no_longer_has_meseta_pkt = builder::message::player_no_longer_has_meseta(area_client, no_longer_has_item.amount);
let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?;
Ok(clients_in_area.into_iter() Ok(clients_in_area.into_iter()
@ -218,7 +218,7 @@ where
.collect()) .collect())
} }
else { else {
Err(ShipError::InvalidItem(ClientItemId(no_longer_has_item.item_id)).into())
Err(ShipError::InvalidItem(ClientItemId(no_longer_has_item.item_id)))
} }
} }
@ -292,7 +292,7 @@ pub async fn update_player_position(id: ClientId,
_ => {}, _ => {},
} }
Ok::<_, ShipError>(()) Ok::<_, ShipError>(())
})}).await?;
})}).await??;
} }
Ok(client_location.get_client_neighbors(id).await?.into_iter() Ok(client_location.get_client_neighbors(id).await?.into_iter()
.map(move |client| { .map(move |client| {

134
src/ship/packet/handler/quest.rs

@ -8,7 +8,6 @@ use crate::ship::location::{ClientLocation, ClientLocationError};
use crate::ship::packet::builder::quest; use crate::ship::packet::builder::quest;
use libpso::util::array_to_utf8; use libpso::util::array_to_utf8;
// TOOD: enum
enum QuestFileType { enum QuestFileType {
Bin, Bin,
Dat Dat
@ -44,16 +43,6 @@ pub async fn send_quest_category_list(id: ClientId,
rooms: &Rooms) rooms: &Rooms)
-> Result<Vec<(ClientId, SendShipPacket)>, ShipError> { -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> {
let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
/*
let mut room = rooms.get_mut(room_id.0)
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut()
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?
.write()
.await;
let qcl = quest::quest_category_list(&room.quests[rql.flag.clamp(0, (room.quests.len() - 1) as u32) as usize]);
room.set_quest_group(rql.flag as usize);
Ok(Box::new(vec![(id, SendShipPacket::QuestCategoryList(qcl))].into_iter()))
*/
let rql = rql.clone(); let rql = rql.clone();
rooms.with_mut(room_id, |room| Box::pin(async move { rooms.with_mut(room_id, |room| Box::pin(async move {
let qcl = quest::quest_category_list(&room.quests[rql.flag.clamp(0, (room.quests.len() - 1) as u32) as usize]); let qcl = quest::quest_category_list(&room.quests[rql.flag.clamp(0, (room.quests.len() - 1) as u32) as usize]);
@ -71,7 +60,7 @@ pub async fn select_quest_category(id: ClientId,
rooms.with(room_id, |room| Box::pin(async move { rooms.with(room_id, |room| Box::pin(async move {
let (_, category_quests) = room.quests[room.quest_group.value()].iter() let (_, category_quests) = room.quests[room.quest_group.value()].iter()
.nth(menuselect.item as usize) .nth(menuselect.item as usize)
.ok_or(ShipError::InvalidQuestCategory(menuselect.item))?;
.ok_or_else(|| ShipError::InvalidQuestCategory(menuselect.item as u16))?;
let ql = quest::quest_list(menuselect.item, category_quests); let ql = quest::quest_list(menuselect.item, category_quests);
Ok(vec![(id, SendShipPacket::QuestOptionList(ql))]) Ok(vec![(id, SendShipPacket::QuestOptionList(ql))])
@ -88,12 +77,12 @@ pub async fn quest_detail(id: ClientId,
rooms.with(room_id, |room| Box::pin(async move { rooms.with(room_id, |room| Box::pin(async move {
let (_, category_quests) = room.quests[room.quest_group.value()].iter() let (_, category_quests) = room.quests[room.quest_group.value()].iter()
.nth(questdetailrequest.category as usize) .nth(questdetailrequest.category as usize)
.ok_or(ShipError::InvalidQuestCategory(questdetailrequest.category as u32))?;
.ok_or_else(|| ShipError::InvalidQuestCategory(questdetailrequest.category))?;
let quest = category_quests.iter() let quest = category_quests.iter()
.find(|q| { .find(|q| {
q.id == questdetailrequest.quest as u16
}).ok_or(ShipError::InvalidQuest(questdetailrequest.quest as u32))?;
q.id == questdetailrequest.quest
}).ok_or_else(|| ShipError::InvalidQuest(questdetailrequest.quest))?;
let qd = quest::quest_detail(quest); let qd = quest::quest_detail(quest);
@ -116,13 +105,13 @@ pub async fn player_chose_quest(id: ClientId,
Box::pin(async move { Box::pin(async move {
let quest = room.quests[room.quest_group.value()].iter() let quest = room.quests[room.quest_group.value()].iter()
.nth(questmenuselect.category as usize) .nth(questmenuselect.category as usize)
.ok_or(ShipError::InvalidQuestCategory(questmenuselect.category as u32))?
.ok_or_else(|| ShipError::InvalidQuestCategory(questmenuselect.category))?
.1 .1
.iter() .iter()
.find(|q| { .find(|q| {
q.id == questmenuselect.quest as u16
q.id == questmenuselect.quest
}) })
.ok_or(ShipError::InvalidQuest(questmenuselect.quest as u32))?
.ok_or_else(|| ShipError::InvalidQuest(questmenuselect.quest))?
.clone(); .clone();
let rare_monster_drops = room.rare_monster_table.clone(); let rare_monster_drops = room.rare_monster_table.clone();
@ -138,11 +127,6 @@ pub async fn player_chose_quest(id: ClientId,
client.done_loading_quest = false; client.done_loading_quest = false;
})).await?; })).await?;
} }
//area_clients.iter().for_each(|c| {
//if let Some(client) = clients.get_mut(&c.client) {
// client.done_loading_quest = false;
//}
//});
Ok(area_clients Ok(area_clients
.into_iter() .into_iter()
.flat_map(move |c| { .flat_map(move |c| {
@ -150,53 +134,6 @@ pub async fn player_chose_quest(id: ClientId,
}) })
.collect()) .collect())
})}).await? })}).await?
/*
let mut room = rooms.get(room_id.0)
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?
.as_ref()
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?
.write()
.await;
/*
let (_, category_quests) = room.quests[room.quest_group.value()].iter()
.nth(questmenuselect.category as usize)
.ok_or(ShipError::InvalidQuestCategory(questmenuselect.category as u32))?;
let quest = category_quests.iter()
.find(|q| {
q.id == questmenuselect.quest as u16
}).ok_or(ShipError::InvalidQuest(questmenuselect.quest as u32))?
.clone();
*/
let quest = room.quests[room.quest_group.value()].iter()
.nth(questmenuselect.category as usize)
.ok_or(ShipError::InvalidQuestCategory(questmenuselect.category as u32))?
.1
.iter()
.find(|q| {
q.id == questmenuselect.quest as u16
})
.ok_or(ShipError::InvalidQuest(questmenuselect.quest as u32))?
.clone();
let rare_monster_drops = room.rare_monster_table.clone();
room.maps.set_quest_data(quest.enemies.clone(), quest.objects.clone(), &rare_monster_drops);
room.map_areas = quest.map_areas.clone();
let bin = quest::quest_header(questmenuselect, &quest.bin_blob, "bin");
let dat = quest::quest_header(questmenuselect, &quest.dat_blob, "dat");
let area_clients = client_location.get_all_clients_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
area_clients.iter().for_each(|c| {
if let Some(client) = clients.get_mut(&c.client) {
client.done_loading_quest = false;
}
});
Ok(Box::new(area_clients.into_iter().flat_map(move |c| {
vec![(c.client, SendShipPacket::QuestHeader(bin.clone())), (c.client, SendShipPacket::QuestHeader(dat.clone()))]
})))
*/
} }
pub async fn quest_file_request(id: ClientId, pub async fn quest_file_request(id: ClientId,
@ -212,12 +149,12 @@ pub async fn quest_file_request(id: ClientId,
let (category_id, quest_id, datatype) = parse_filename(&quest_file_request.filename)?; let (category_id, quest_id, datatype) = parse_filename(&quest_file_request.filename)?;
let (_, category_quests) = room.quests[room.quest_group.value()].iter() let (_, category_quests) = room.quests[room.quest_group.value()].iter()
.nth(category_id as usize) .nth(category_id as usize)
.ok_or(ShipError::InvalidQuestCategory(category_id as u32))?;
.ok_or_else(|| ShipError::InvalidQuestCategory(category_id))?;
let quest = category_quests.iter() let quest = category_quests.iter()
.find(|q| { .find(|q| {
q.id == quest_id as u16
}).ok_or(ShipError::InvalidQuest(quest_id as u32))?;
q.id == quest_id
}).ok_or_else(|| ShipError::InvalidQuest(quest_id))?;
let blob = match datatype { let blob = match datatype {
QuestFileType::Bin => &quest.bin_blob, QuestFileType::Bin => &quest.bin_blob,
@ -245,12 +182,12 @@ pub async fn quest_chunk_ack(id: ClientId,
let (category_id, quest_id, datatype) = parse_filename(&quest_chunk_ack.filename)?; let (category_id, quest_id, datatype) = parse_filename(&quest_chunk_ack.filename)?;
let (_, category_quests) = room.quests[room.quest_group.value()].iter() let (_, category_quests) = room.quests[room.quest_group.value()].iter()
.nth(category_id as usize) .nth(category_id as usize)
.ok_or(ShipError::InvalidQuestCategory(category_id as u32))?;
.ok_or_else(|| ShipError::InvalidQuestCategory(category_id))?;
let quest = category_quests.iter() let quest = category_quests.iter()
.find(|q| { .find(|q| {
q.id == quest_id q.id == quest_id
}).ok_or(ShipError::InvalidQuest(quest_id as u32))?;
}).ok_or_else(|| ShipError::InvalidQuest(quest_id))?;
let blob = match datatype { let blob = match datatype {
QuestFileType::Bin => &quest.bin_blob, QuestFileType::Bin => &quest.bin_blob,
@ -268,41 +205,6 @@ pub async fn quest_chunk_ack(id: ClientId,
Ok(vec![(id, SendShipPacket::QuestChunk(qc))]) Ok(vec![(id, SendShipPacket::QuestChunk(qc))])
})).await? })).await?
/*
let mut room = rooms.get(room_id.0)
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?
.write()
.await
.as_ref()
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?;
let (category_id, quest_id, datatype) = parse_filename(&quest_chunk_ack.filename)?;
let (_, category_quests) = room.quests[room.quest_group.value()].iter()
.nth(category_id as usize)
.ok_or(ShipError::InvalidQuestCategory(category_id as u32))?;
let quest = category_quests.iter()
.find(|q| {
q.id == quest_id
}).ok_or(ShipError::InvalidQuest(quest_id as u32))?;
let blob = match datatype {
QuestFileType::Bin => &quest.bin_blob,
QuestFileType::Dat => &quest.dat_blob,
};
let mut blob_cursor = Cursor::new(&**blob);
blob_cursor.seek(SeekFrom::Start((quest_chunk_ack.chunk_num as u64 + 1) * 0x400))?;
let mut subblob = [0u8; 0x400];
let blob_length = blob_cursor.read(&mut subblob)?;
if blob_length == 0 {
return Ok(Box::new(None.into_iter()));
}
let qc = quest::quest_chunk(quest_chunk_ack.chunk_num + 1, quest_chunk_ack.filename, subblob, blob_length);
Ok(Box::new(vec![(id, SendShipPacket::QuestChunk(qc))].into_iter()))
*/
} }
pub async fn done_loading_quest(id: ClientId, pub async fn done_loading_quest(id: ClientId,
@ -315,14 +217,14 @@ pub async fn done_loading_quest(id: ClientId,
let area_clients = client_location.get_all_clients_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let area_clients = client_location.get_all_clients_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let all_loaded = area_clients.iter() let all_loaded = area_clients.iter()
.map(|client| async {
clients.with(client.client, |client| Box::pin(async move {
client.done_loading_quest
}))
})
.map(|client|
clients.with(client.client, |client| Box::pin(async move {
client.done_loading_quest
}))
)
.collect::<FuturesOrdered<_>>() .collect::<FuturesOrdered<_>>()
.all(|c| async move { .all(|c| async move {
c.await.unwrap_or(false)
c.unwrap_or(false)
}).await; }).await;
if all_loaded { if all_loaded {

60
src/ship/packet/handler/room.rs

@ -1,16 +1,16 @@
use std::convert::{TryFrom, Into};
use futures::stream::StreamExt;
use libpso::packet::ship::*; use libpso::packet::ship::*;
use libpso::packet::messages::*; use libpso::packet::messages::*;
use crate::common::serverstate::ClientId; use crate::common::serverstate::ClientId;
use crate::common::leveltable::LEVEL_TABLE; use crate::common::leveltable::LEVEL_TABLE;
use crate::ship::ship::{SendShipPacket, ShipError, Clients}; use crate::ship::ship::{SendShipPacket, ShipError, Clients};
use crate::ship::room::Rooms; use crate::ship::room::Rooms;
use crate::ship::location::{ClientLocation, RoomId, RoomLobby, ClientLocationError, GetAreaError};
use crate::ship::location::{ClientLocation, RoomId, RoomLobby, GetAreaError};
use crate::ship::packet::builder; use crate::ship::packet::builder;
use crate::ship::room; use crate::ship::room;
use crate::ship::items::state::ItemState; use crate::ship::items::state::ItemState;
use std::convert::{TryFrom, Into};
use async_std::sync::{Arc, RwLock};
use futures::stream::{FuturesOrdered, StreamExt};
pub async fn create_room(id: ClientId, pub async fn create_room(id: ClientId,
create_room: CreateRoom, create_room: CreateRoom,
@ -39,7 +39,6 @@ pub async fn create_room(id: ClientId,
let area_client = client_location.get_local_client(id).await?; let area_client = client_location.get_local_client(id).await?;
let lobby_neighbors = client_location.get_client_neighbors(id).await?; let lobby_neighbors = client_location.get_client_neighbors(id).await?;
//let room_id = client_location.create_new_room(id).await.map_err(Into::<ClientLocationError>::into)?;
let room_id = client_location.create_new_room(id).await?; let room_id = client_location.create_new_room(id).await?;
let room = clients.with(id, |client| { let room = clients.with(id, |client| {
let mut item_state = item_state.clone(); let mut item_state = item_state.clone();
@ -66,7 +65,6 @@ pub async fn create_room(id: ClientId,
Ok(result) Ok(result)
} }
// TODO: remove unwraps
pub async fn room_name_request(id: ClientId, pub async fn room_name_request(id: ClientId,
client_location: &ClientLocation, client_location: &ClientLocation,
rooms: &Rooms) rooms: &Rooms)
@ -81,7 +79,6 @@ pub async fn room_name_request(id: ClientId,
})).await })).await
}, },
RoomLobby::Lobby(_) => Err(GetAreaError::NotInRoom.into()) RoomLobby::Lobby(_) => Err(GetAreaError::NotInRoom.into())
//RoomLobby::Lobby(_) => Err(ShipError::ClientLocationError(GetAreaError::NotInRoom))
} }
} }
@ -125,8 +122,7 @@ pub async fn join_room(id: ClientId,
let original_room_clients = client_location.get_clients_in_room(room_id).await?; let original_room_clients = client_location.get_clients_in_room(room_id).await?;
client_location.add_client_to_room(id, room_id).await?; client_location.add_client_to_room(id, room_id).await?;
let area_client = client_location.get_local_client(id).await?; let area_client = client_location.get_local_client(id).await?;
//let original_leader = client_location.get_area_leader(original_area).await.unwrap();
let room_leader = client_location.get_room_leader(room_id).await.unwrap();
let room_leader = client_location.get_room_leader(room_id).await?;
clients.with(id, |client| { clients.with(id, |client| {
let mut item_state = item_state.clone(); let mut item_state = item_state.clone();
@ -138,14 +134,13 @@ pub async fn join_room(id: ClientId,
let clients = clients.clone(); let clients = clients.clone();
let client_location = client_location.clone(); let client_location = client_location.clone();
Box::pin(async move { Box::pin(async move {
builder::room::join_room(id, &clients, &client_location, room_id, &room).await
builder::room::join_room(id, &clients, &client_location, room_id, room).await
})}).await??; })}).await??;
let add_to = clients.with(id, |client| { let add_to = clients.with(id, |client| {
let item_state = item_state.clone(); let item_state = item_state.clone();
Box::pin(async move { Box::pin(async move {
builder::room::add_to_room(id, client, &area_client, &room_leader, &item_state, room_id).await builder::room::add_to_room(id, client, &area_client, &room_leader, &item_state, room_id).await
})}).await??; })}).await??;
//let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), original_leader.local_client.id()));
rooms.with_mut(room_id, |room| Box::pin(async move { rooms.with_mut(room_id, |room| Box::pin(async move {
room.bursting = true; room.bursting = true;
@ -161,7 +156,7 @@ pub async fn join_room(id: ClientId,
async move { async move {
client_location.get_area_leader(original_area).await.ok().map(|leader| { client_location.get_area_leader(original_area).await.ok().map(|leader| {
let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())); let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id()));
(c.client, leave_lobby.clone())
(c.client, leave_lobby)
}) })
} }
}) })
@ -169,37 +164,6 @@ pub async fn join_room(id: ClientId,
.await .await
) )
.collect()) .collect())
/*
if let Ok(leader) = client_location.get_area_leader(original_area).await {
let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id()));
result.extend(original_neighbors.into_iter()
.map(move |c| (c.client, leave_lobby.clone())))
}
*/
//Ok(result)
/*
if let Some(room) = &mut *rooms.get(pkt.item as usize).ok_or(ShipError::InvalidRoom(pkt.item))?.write().await {
let mut result: Box<dyn Iterator<Item=(ClientId, SendShipPacket)> + Send> = Box::new(
vec![(id, SendShipPacket::JoinRoom(join_room))]
.into_iter()
.chain(original_room_clients.into_iter()
.map(move |c| (c.client, SendShipPacket::AddToRoom(add_to.clone())))
));
if let Ok(leader) = client_location.get_area_leader(original_area).await {
let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id()));
result = Box::new(result.chain(original_neighbors.into_iter()
.map(move |c| (c.client, leave_lobby.clone()))))
}
Ok(result.collect())
} else {
Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Game is no longer active".into())))])
}
*/
} }
pub async fn done_bursting(id: ClientId, pub async fn done_bursting(id: ClientId,
@ -230,7 +194,6 @@ pub async fn request_room_list(id: ClientId,
client_location: &ClientLocation, client_location: &ClientLocation,
rooms: &Rooms) rooms: &Rooms)
-> Vec<(ClientId, SendShipPacket)> { -> Vec<(ClientId, SendShipPacket)> {
//let active_room_list = futures::stream::iter(rooms.iter())
let active_room_list = rooms.stream() let active_room_list = rooms.stream()
.enumerate() .enumerate()
.filter_map(|(i, r)| async move { .filter_map(|(i, r)| async move {
@ -270,17 +233,16 @@ pub async fn request_room_list(id: ClientId,
pub async fn cool_62(id: ClientId, pub async fn cool_62(id: ClientId,
cool_62: Like62ButCooler, cool_62: Like62ButCooler,
client_location: &ClientLocation) client_location: &ClientLocation)
-> Vec<(ClientId, SendShipPacket)> {
-> Result<Vec<(ClientId, SendShipPacket)>, ShipError> {
let target = cool_62.flag as u8; let target = cool_62.flag as u8;
let cool_62 = cool_62.clone(); let cool_62 = cool_62.clone();
client_location
Ok(client_location
.get_client_neighbors(id) .get_client_neighbors(id)
.await
.unwrap()
.await?
.into_iter() .into_iter()
.filter(move |client| client.local_client.id() == target) .filter(move |client| client.local_client.id() == target)
.map(move |client| { .map(move |client| {
(client.client, SendShipPacket::Like62ButCooler(cool_62.clone())) (client.client, SendShipPacket::Like62ButCooler(cool_62.clone()))
}) })
.collect()
.collect())
} }

2
src/ship/packet/handler/ship.rs

@ -15,7 +15,7 @@ pub fn block_list(id: ClientId, shipname: &str, num_blocks: usize) -> Vec<(Clien
pub fn selected_ship(id: ClientId, menuselect: MenuSelect, ship_list: &[Ship]) pub fn selected_ship(id: ClientId, menuselect: MenuSelect, ship_list: &[Ship])
-> Result<Vec<(ClientId, SendShipPacket)>, ShipError> { -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> {
let ship = ship_list.get(menuselect.item as usize).ok_or(ShipError::InvalidShip(menuselect.item as usize))?;
let ship = ship_list.get(menuselect.item as usize).ok_or_else(|| ShipError::InvalidShip(menuselect.item as usize))?;
let ip = u32::from_ne_bytes(ship.ip.octets()); let ip = u32::from_ne_bytes(ship.ip.octets());
Ok(vec![(id, SendShipPacket::RedirectClient(RedirectClient::new(ip, ship.port)))]) Ok(vec![(id, SendShipPacket::RedirectClient(RedirectClient::new(ip, ship.port)))])
} }

12
src/ship/packet/handler/trade.rs

@ -154,7 +154,7 @@ pub async fn trade_request(id: ClientId,
this.meseta += amount as usize; this.meseta += amount as usize;
} }
else { else {
let item = inventory.get_by_client_id(&ClientItemId(item_id)).ok_or(ItemStateError::InvalidItemId(ClientItemId(item_id)))?;
let item = inventory.get_by_client_id(&ClientItemId(item_id)).ok_or_else(|| ItemStateError::InvalidItemId(ClientItemId(item_id)))?;
match &item.item { match &item.item {
InventoryItemDetail::Individual(_) => { InventoryItemDetail::Individual(_) => {
@ -192,7 +192,7 @@ pub async fn trade_request(id: ClientId,
this.meseta -= amount as usize; this.meseta -= amount as usize;
} }
else { else {
let item = inventory.get_by_client_id(&ClientItemId(item_id)).ok_or(ItemStateError::InvalidItemId(ClientItemId(item_id)))?;
let item = inventory.get_by_client_id(&ClientItemId(item_id)).ok_or_else(|| ItemStateError::InvalidItemId(ClientItemId(item_id)))?;
match &item.item { match &item.item {
InventoryItemDetail::Individual(_) => { InventoryItemDetail::Individual(_) => {
@ -207,9 +207,9 @@ pub async fn trade_request(id: ClientId,
}) })
.ok_or(TradeError::InvalidItemId(ClientItemId(item_id)))?; .ok_or(TradeError::InvalidItemId(ClientItemId(item_id)))?;
match this.items[trade_item_index].stacked().ok_or(ItemStateError::InvalidItemId(ClientItemId(item_id)))?.1.cmp(&(amount as usize)) {
match this.items[trade_item_index].stacked().ok_or_else(|| ItemStateError::InvalidItemId(ClientItemId(item_id)))?.1.cmp(&(amount as usize)) {
std::cmp::Ordering::Greater => { std::cmp::Ordering::Greater => {
*this.items[trade_item_index].stacked_mut().ok_or(ItemStateError::InvalidItemId(ClientItemId(item_id)))?.1 -= amount as usize;
*this.items[trade_item_index].stacked_mut().ok_or_else(|| ItemStateError::InvalidItemId(ClientItemId(item_id)))?.1 -= amount as usize;
}, },
std::cmp::Ordering::Equal => { std::cmp::Ordering::Equal => {
this.items.remove(trade_item_index); this.items.remove(trade_item_index);
@ -314,7 +314,7 @@ async fn inner_items_to_trade(id: ClientId,
Ok::<_, ShipError>((this, other_inventory)) Ok::<_, ShipError>((this, other_inventory))
})}).await??; })}).await??;
if items_to_trade.count as usize != (this.items.len() + (if this.meseta != 0 { 1 } else { 0 })) {
if items_to_trade.count as usize != (this.items.len() + usize::from(this.meseta != 0)) {
return Err(TradeError::MismatchedTradeItems.into()) return Err(TradeError::MismatchedTradeItems.into())
} }
@ -342,7 +342,7 @@ async fn inner_items_to_trade(id: ClientId,
} }
else { else {
let real_item = this_inventory.get_by_client_id(&ClientItemId(item.item_id)) let real_item = this_inventory.get_by_client_id(&ClientItemId(item.item_id))
.ok_or(ItemStateError::InvalidItemId(ClientItemId(item.item_id)))?;
.ok_or_else(|| ItemStateError::InvalidItemId(ClientItemId(item.item_id)))?;
let real_trade_item = this.items let real_trade_item = this.items
.iter() .iter()
.find(|i| i.item_id() == ClientItemId(item.item_id)) .find(|i| i.item_id() == ClientItemId(item.item_id))

44
src/ship/room.rs

@ -1,16 +1,13 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::{From, Into, TryFrom, TryInto}; use std::convert::{From, Into, TryFrom, TryInto};
use std::path::PathBuf; use std::path::PathBuf;
use async_std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::future::Future;
use futures::stream::{Stream, StreamExt, FuturesOrdered};
use async_std::sync::{Arc, RwLock, RwLockReadGuard};
use futures::future::BoxFuture; use futures::future::BoxFuture;
use futures::stream::{FuturesOrdered, Stream};
use thiserror::Error; use thiserror::Error;
use std::ops::Deref;
use rand::Rng; use rand::Rng;
use crate::ship::map::Maps; use crate::ship::map::Maps;
use crate::ship::drops::DropTable; use crate::ship::drops::DropTable;
use crate::entity::character::SectionID; use crate::entity::character::SectionID;
@ -19,8 +16,7 @@ use crate::ship::map::area::MapAreaLookup;
use crate::ship::map::enemy::RareMonsterAppearTable; use crate::ship::map::enemy::RareMonsterAppearTable;
use crate::ship::quests; use crate::ship::quests;
use crate::ship::ship::ShipError; use crate::ship::ship::ShipError;
use crate::ship::location::{ClientLocation, RoomLobby, MAX_ROOMS, ClientLocationError, GetNeighborError, GetClientsError, GetAreaError, RoomId};
use crate::ship::location::{MAX_ROOMS, RoomId};
#[derive(Clone)] #[derive(Clone)]
@ -32,28 +28,11 @@ impl Default for Rooms {
} }
} }
/*
#[derive(escher::Rebindable)]
struct BorrowedRoom<'a> {
lock: RwLockReadGuard<'a, Option<RoomState>>,
room: &'a Option<RoomState>,
}
impl<'a> std::ops::Deref for BorrowedRoom<'a> {
type Target = RoomState;
fn deref(&self) -> &Self::Target {
&self.room
}
}
*/
impl Rooms { impl Rooms {
pub async fn add(&self, room_id: RoomId, room: RoomState) -> Result<(), ShipError> { pub async fn add(&self, room_id: RoomId, room: RoomState) -> Result<(), ShipError> {
*self.0 *self.0
.get(room_id.0) .get(room_id.0)
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?
.ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?
.write() .write()
.await = Some(room); .await = Some(room);
Ok(()) Ok(())
@ -86,7 +65,7 @@ impl Rooms {
{ {
let room = self.0 let room = self.0
.get(room_id.0) .get(room_id.0)
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?
.ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?
.read() .read()
.await; .await;
if let Some(room) = room.as_ref() { if let Some(room) = room.as_ref() {
@ -104,7 +83,7 @@ impl Rooms {
{ {
let mut room = self.0 let mut room = self.0
.get(room_id.0) .get(room_id.0)
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?
.ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?
.write() .write()
.await; .await;
@ -116,7 +95,7 @@ impl Rooms {
} }
} }
pub async fn get<'a>(&'a self, room_id: RoomId) -> RwLockReadGuard<'a, Option<RoomState>> {
pub async fn get(&self, room_id: RoomId) -> RwLockReadGuard<Option<RoomState>> {
self.0 self.0
.get(room_id.0) .get(room_id.0)
.unwrap() .unwrap()
@ -124,7 +103,7 @@ impl Rooms {
.await .await
} }
pub fn stream<'a>(&'a self) -> impl Stream<Item = RwLockReadGuard<'a, Option<RoomState>>> + 'a {
pub fn stream(&self) -> impl Stream<Item = RwLockReadGuard<Option<RoomState>>> {
self.0 self.0
.iter() .iter()
.map(|room| async move { .map(|room| async move {
@ -136,11 +115,6 @@ impl Rooms {
} }
} }
#[derive(Debug, Error)] #[derive(Debug, Error)]
#[error("")] #[error("")]
pub enum RoomCreationError { pub enum RoomCreationError {

225
src/ship/ship.rs

@ -9,7 +9,7 @@ use rand::Rng;
use thiserror::Error; use thiserror::Error;
use libpso::packet::ship::*; use libpso::packet::ship::*;
use libpso::packet::login::{RedirectClient, Login, LoginResponse, Session, ShipList};
use libpso::packet::login::{RedirectClient, Login, LoginResponse, ShipList};
use libpso::packet::messages::*; use libpso::packet::messages::*;
use libpso::{PacketParseError, PSOPacket}; use libpso::{PacketParseError, PSOPacket};
use libpso::crypto::bb::PSOBBCipher; use libpso::crypto::bb::PSOBBCipher;
@ -24,17 +24,15 @@ use crate::common::interserver::{AuthToken, Ship, ServerId, InterserverActor, Lo
use crate::login::character::SHIP_MENU_ID; use crate::login::character::SHIP_MENU_ID;
use crate::entity::gateway::{EntityGateway, GatewayError}; use crate::entity::gateway::{EntityGateway, GatewayError};
use crate::entity::account::{UserAccountEntity, UserSettingsEntity};
use crate::entity::character::{CharacterEntity, SectionID};
use crate::entity::item;
use crate::entity::character::SectionID;
use crate::ship::location::{ClientLocation, RoomLobby, MAX_ROOMS, ClientLocationError, GetNeighborError, GetClientsError, GetAreaError, RoomId};
use crate::ship::location::{ClientLocation, RoomLobby, ClientLocationError, RoomId};
use crate::ship::items; use crate::ship::items;
use crate::ship::room; use crate::ship::room;
use crate::ship::map::{MapsError, MapAreaError, MapArea};
use crate::ship::map::{MapsError, MapAreaError};
use crate::ship::packet::handler; use crate::ship::packet::handler;
use crate::ship::shops::{WeaponShop, ToolShop, ArmorShop, WeaponShopItem, ToolShopItem, ArmorShopItem};
use crate::ship::shops::{WeaponShop, ToolShop, ArmorShop};
use crate::ship::trade::TradeState; use crate::ship::trade::TradeState;
// TODO: remove once stuff settles down // TODO: remove once stuff settles down
@ -56,16 +54,7 @@ pub enum ShipError {
#[error("too many clients")] #[error("too many clients")]
TooManyClients, TooManyClients,
#[error("client error location {0}")] #[error("client error location {0}")]
//ClientLocationError(#[from] ClientLocationError),
ClientLocationError(ClientLocationError), ClientLocationError(ClientLocationError),
/*
#[error("get neighbor error {0}")]
GetNeighborError(#[from] GetNeighborError),
#[error("get clients error {0}")]
GetClientsError(#[from] GetClientsError),
#[error("get area error {0}")]
GetAreaError(#[from] GetAreaError),
*/
#[error("maps error {0}")] #[error("maps error {0}")]
MapsError(#[from] MapsError), MapsError(#[from] MapsError),
#[error("map area error {0}")] #[error("map area error {0}")]
@ -89,9 +78,9 @@ pub enum ShipError {
#[error("box already dropped item {0} {1}")] #[error("box already dropped item {0} {1}")]
BoxAlreadyDroppedItem(ClientId, u16), BoxAlreadyDroppedItem(ClientId, u16),
#[error("invalid quest category {0}")] #[error("invalid quest category {0}")]
InvalidQuestCategory(u32),
InvalidQuestCategory(u16),
#[error("invalid quest {0}")] #[error("invalid quest {0}")]
InvalidQuest(u32),
InvalidQuest(u16),
#[error("invalid quest filename {0}")] #[error("invalid quest filename {0}")]
InvalidQuestFilename(String), InvalidQuestFilename(String),
#[error("io error {0}")] #[error("io error {0}")]
@ -118,24 +107,10 @@ pub enum ShipError {
MessageError(#[from] crate::ship::packet::handler::direct_message::MessageError), MessageError(#[from] crate::ship::packet::handler::direct_message::MessageError),
#[error("room creation error {0}")] #[error("room creation error {0}")]
RoomCreationError(#[from] room::RoomCreationError), RoomCreationError(#[from] room::RoomCreationError),
#[error("channel send error {0}")]
SendError(#[from] async_std::channel::SendError<ShipMessage>),
} }
/*
impl From<ClientLocationError> for ShipError {
fn from(other: &ClientLocationError) -> ShipError {
}
}
*/
/*
impl<I: Into<ClientLocationError>> Into<ShipError> for I {
fn into(other: I) -> ShipError {
ShipError::ClientLocationError(other.into())
}
}
*/
impl<I: Into<ClientLocationError>> From<I> for ShipError { impl<I: Into<ClientLocationError>> From<I> for ShipError {
fn from(other: I) -> ShipError { fn from(other: I) -> ShipError {
ShipError::ClientLocationError(other.into()) ShipError::ClientLocationError(other.into())
@ -420,45 +395,23 @@ impl<EG: EntityGateway + Clone + 'static> ShipServerStateBuilder<EG> {
} }
#[derive(Clone)]
#[derive(Clone, Default)]
pub struct Block { pub struct Block {
client_location: ClientLocation, client_location: ClientLocation,
pub rooms: room::Rooms, pub rooms: room::Rooms,
} }
impl Default for Block {
fn default() -> Block {
Block {
client_location: ClientLocation::default(),
rooms: room::Rooms::default(),
//rooms: core::array::from_fn(|_| Arc::new(RwLock::new(None))),
}
}
}
/*
impl Block {
fn with<F, T>(&self, func: F) -> T
where
T: Send,
F: FnOnce(&Block) -> T,
{
func(self)
}
}
*/
#[derive(Clone)] #[derive(Clone)]
pub struct Blocks(pub Vec<Block>); pub struct Blocks(pub Vec<Block>);
impl Blocks { impl Blocks {
async fn from_client(&mut self, id: ClientId, clients: &Clients) -> Result<&mut Block, ShipError> {
async fn get_from_client(&mut self, id: ClientId, clients: &Clients) -> Result<&mut Block, ShipError> {
let block = clients.with(id, |client| Box::pin(async move { let block = clients.with(id, |client| Box::pin(async move {
client.block client.block
})).await?; })).await?;
self.0 self.0
.get_mut(block) .get_mut(block)
.ok_or(ShipError::InvalidBlock(block))
.ok_or_else(|| ShipError::InvalidBlock(block))
} }
} }
@ -477,7 +430,6 @@ pub struct ShipServerState<EG: EntityGateway + Clone + 'static> {
auth_token: AuthToken, auth_token: AuthToken,
ship_list: Vec<Ship>, ship_list: Vec<Ship>,
//shipgate_sender: Option<Box<dyn Fn(ShipMessage) + Send + Sync>>,
shipgate_sender: Option<channel::Sender<ShipMessage>>, shipgate_sender: Option<channel::Sender<ShipMessage>>,
trades: TradeState, trades: TradeState,
} }
@ -490,42 +442,42 @@ impl<EG: EntityGateway + Clone + 'static> ShipServerState<EG> {
async fn message(&mut self, id: ClientId, msg: Message) -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> { async fn message(&mut self, id: ClientId, msg: Message) -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> {
Ok(match msg.msg { Ok(match msg.msg {
GameMessage::RequestExp(request_exp) => { GameMessage::RequestExp(request_exp) => {
let block = self.blocks.from_client(id, &self.clients).await?;
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::message::request_exp(id, request_exp, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms).await? handler::message::request_exp(id, request_exp, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms).await?
}, },
GameMessage::PlayerDropItem(player_drop_item) => { GameMessage::PlayerDropItem(player_drop_item) => {
let block = self.blocks.from_client(id, &self.clients).await?;
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::message::player_drop_item(id, player_drop_item, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await? handler::message::player_drop_item(id, player_drop_item, &mut self.entity_gateway, &block.client_location, &self.clients, &block.rooms, &mut self.item_state).await?
}, },
GameMessage::DropCoordinates(drop_coordinates) => { GameMessage::DropCoordinates(drop_coordinates) => {
let block = self.blocks.from_client(id, &self.clients).await?;
handler::message::drop_coordinates(id, drop_coordinates, &block.client_location, &mut self.clients, &block.rooms).await?
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::message::drop_coordinates(id, drop_coordinates, &block.client_location, &self.clients, &block.rooms).await?
}, },
GameMessage::PlayerNoLongerHasItem(no_longer_has_item) => { GameMessage::PlayerNoLongerHasItem(no_longer_has_item) => {
let block = self.blocks.from_client(id, &self.clients).await?;
handler::message::no_longer_has_item(id, no_longer_has_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await?
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::message::no_longer_has_item(id, no_longer_has_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).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(_) => {
let block = self.blocks.from_client(id, &self.clients).await?;
handler::message::update_player_position(id, msg, &mut self.clients, &block.client_location, &block.rooms).await?
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::message::update_player_position(id, msg, &self.clients, &block.client_location, &block.rooms).await?
}, },
GameMessage::ChargeAttack(charge_attack) => { GameMessage::ChargeAttack(charge_attack) => {
let block = self.blocks.from_client(id, &self.clients).await?;
handler::message::charge_attack(id, charge_attack, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await?
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::message::charge_attack(id, charge_attack, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await?
}, },
GameMessage::PlayerUseItem(player_use_item) => { GameMessage::PlayerUseItem(player_use_item) => {
let block = self.blocks.from_client(id, &self.clients).await?;
handler::message::player_uses_item(id, player_use_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await?
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::message::player_uses_item(id, player_use_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await?
}, },
GameMessage::PlayerUsedMedicalCenter(player_used_medical_center) => { GameMessage::PlayerUsedMedicalCenter(player_used_medical_center) => {
let block = self.blocks.from_client(id, &self.clients).await?;
handler::message::player_used_medical_center(id, player_used_medical_center, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await?
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::message::player_used_medical_center(id, player_used_medical_center, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await?
}, },
GameMessage::PlayerFeedMag(player_feed_mag) => { GameMessage::PlayerFeedMag(player_feed_mag) => {
let block = self.blocks.from_client(id, &self.clients).await?;
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::message::player_feed_mag(id, player_feed_mag, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? handler::message::player_feed_mag(id, player_feed_mag, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await?
}, },
GameMessage::PlayerEquipItem(player_equip_item) => { GameMessage::PlayerEquipItem(player_equip_item) => {
@ -538,11 +490,11 @@ impl<EG: EntityGateway + Clone + 'static> ShipServerState<EG> {
handler::message::player_sorts_items(id, sort_items, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? handler::message::player_sorts_items(id, sort_items, &mut self.entity_gateway, &self.clients, &mut self.item_state).await?
}, },
GameMessage::PlayerSoldItem(player_sold_item) => { GameMessage::PlayerSoldItem(player_sold_item) => {
handler::message::player_sells_item(id, player_sold_item, &mut self.entity_gateway, &mut self.clients, &mut self.item_state).await?
handler::message::player_sells_item(id, player_sold_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await?
}, },
_ => { _ => {
let cmsg = msg.clone(); let cmsg = msg.clone();
let block = self.blocks.from_client(id, &self.clients).await?;
let block = self.blocks.get_from_client(id, &self.clients).await?;
block.client_location.get_client_neighbors(id).await.unwrap().into_iter() block.client_location.get_client_neighbors(id).await.unwrap().into_iter()
.map(move |client| { .map(move |client| {
(client.client, SendShipPacket::Message(cmsg.clone())) (client.client, SendShipPacket::Message(cmsg.clone()))
@ -554,7 +506,7 @@ impl<EG: EntityGateway + Clone + 'static> ShipServerState<EG> {
async fn direct_message(&mut self, id: ClientId, msg: DirectMessage) -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> { async fn direct_message(&mut self, id: ClientId, msg: DirectMessage) -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> {
let target = msg.flag; let target = msg.flag;
let block = self.blocks.from_client(id, &self.clients).await?;
let block = self.blocks.get_from_client(id, &self.clients).await?;
Ok(match msg.msg { Ok(match msg.msg {
GameMessage::GuildcardSend(guildcard_send) => { GameMessage::GuildcardSend(guildcard_send) => {
handler::direct_message::guildcard_send(id, guildcard_send, target, &block.client_location, &self.clients).await? handler::direct_message::guildcard_send(id, guildcard_send, target, &block.client_location, &self.clients).await?
@ -575,7 +527,7 @@ impl<EG: EntityGateway + Clone + 'static> ShipServerState<EG> {
handler::direct_message::bank_interaction(id, bank_interaction, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? handler::direct_message::bank_interaction(id, bank_interaction, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await?
}, },
GameMessage::ShopRequest(shop_request) => { GameMessage::ShopRequest(shop_request) => {
handler::direct_message::shop_request(id, shop_request, &block.client_location, &self.clients, &block.rooms, &mut self.shops).await?
handler::direct_message::shop_request(id, shop_request, &block.client_location, &self.clients, &block.rooms, &self.shops).await?
}, },
GameMessage::BuyItem(buy_item) => { GameMessage::BuyItem(buy_item) => {
handler::direct_message::buy_item(id, buy_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await? handler::direct_message::buy_item(id, buy_item, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state).await?
@ -630,11 +582,6 @@ impl<EG: EntityGateway + Clone> ServerState for ShipServerState<EG> {
})).await { })).await {
self.entity_gateway.set_character_playtime(&char_id, char_playtime).await?; self.entity_gateway.set_character_playtime(&char_id, char_playtime).await?;
} }
/*
if let Some(client) = self.clients.get_mut(&id) {
client.update_playtime();
self.entity_gateway.set_character_playtime(&client.character.id, client.character.playtime).await?;
}*/
Ok(match pkt { Ok(match pkt {
RecvShipPacket::Login(login) => { RecvShipPacket::Login(login) => {
@ -645,14 +592,14 @@ impl<EG: EntityGateway + Clone> ServerState for ShipServerState<EG> {
.collect() .collect()
}, },
RecvShipPacket::QuestDetailRequest(questdetailrequest) => { RecvShipPacket::QuestDetailRequest(questdetailrequest) => {
let block = self.blocks.from_client(id, &self.clients).await?;
let block = self.blocks.get_from_client(id, &self.clients).await?;
match questdetailrequest.menu { match questdetailrequest.menu {
QUEST_SELECT_MENU_ID => handler::quest::quest_detail(id, questdetailrequest, &block.client_location, &mut block.rooms).await?,
QUEST_SELECT_MENU_ID => handler::quest::quest_detail(id, questdetailrequest, &block.client_location, &block.rooms).await?,
_ => unreachable!(), _ => unreachable!(),
} }
}, },
RecvShipPacket::MenuSelect(menuselect) => { RecvShipPacket::MenuSelect(menuselect) => {
let block = self.blocks.from_client(id, &self.clients).await?;
let block = self.blocks.get_from_client(id, &self.clients).await?;
match menuselect.menu { match menuselect.menu {
SHIP_MENU_ID => { SHIP_MENU_ID => {
let leave_lobby = handler::lobby::remove_from_lobby(id, &mut block.client_location).await.into_iter().into_iter().flatten(); let leave_lobby = handler::lobby::remove_from_lobby(id, &mut block.client_location).await.into_iter().into_iter().flatten();
@ -664,73 +611,39 @@ impl<EG: EntityGateway + Clone> ServerState for ShipServerState<EG> {
let select_block = handler::lobby::block_selected(id, menuselect, &self.clients, &self.item_state).await?.into_iter(); let select_block = handler::lobby::block_selected(id, menuselect, &self.clients, &self.item_state).await?.into_iter();
leave_lobby.chain(select_block).collect() leave_lobby.chain(select_block).collect()
} }
ROOM_MENU_ID => handler::room::join_room(id, menuselect, &mut block.client_location, &self.clients, &mut self.item_state, &mut block.rooms).await?,
QUEST_CATEGORY_MENU_ID => handler::quest::select_quest_category(id, menuselect, &block.client_location, &mut block.rooms).await?,
ROOM_MENU_ID => handler::room::join_room(id, menuselect, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms).await?,
QUEST_CATEGORY_MENU_ID => handler::quest::select_quest_category(id, menuselect, &block.client_location, &block.rooms).await?,
_ => unreachable!(), _ => unreachable!(),
} }
}, },
RecvShipPacket::QuestMenuSelect(questmenuselect) => { RecvShipPacket::QuestMenuSelect(questmenuselect) => {
let block = self.blocks.from_client(id, &self.clients).await?;
handler::quest::player_chose_quest(id, questmenuselect, &mut self.clients, &block.client_location, &mut block.rooms).await?
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::quest::player_chose_quest(id, questmenuselect, &self.clients, &block.client_location, &block.rooms).await?
}, },
RecvShipPacket::MenuDetail(menudetail) => { RecvShipPacket::MenuDetail(menudetail) => {
let block = self.blocks.from_client(id, &self.clients).await?;
handler::lobby::get_room_tab_info(id, menudetail, &mut block.client_location, &self.clients, &mut block.rooms).await?
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::lobby::get_room_tab_info(id, menudetail, &mut block.client_location, &self.clients).await?
}, },
RecvShipPacket::RoomPasswordReq(room_password_req) => { RecvShipPacket::RoomPasswordReq(room_password_req) => {
let block = self.blocks.from_client(id, &self.clients).await?;
/*
let password = room_password_req.password;
let correct_password = block.rooms.with(RoomId(room_password_req.item as usize), |room| Box::pin(async move {
password == room.password
})).await?;
*/
let block = self.blocks.get_from_client(id, &self.clients).await?;
let room_password = block.rooms.with(RoomId(room_password_req.item as usize), |room| Box::pin(async move { let room_password = block.rooms.with(RoomId(room_password_req.item as usize), |room| Box::pin(async move {
room.password room.password
})).await?; })).await?;
/*
let correct_password = room_password_req.password == block.rooms
.get(RoomId(room_password_req.item as usize))
.await
.map(|room| room.password)
.unwrap_or_else(false);
*/
//if correct_password {
if room_password_req.password == room_password { if room_password_req.password == room_password {
let menuselect = MenuSelect { let menuselect = MenuSelect {
menu: room_password_req.menu, menu: room_password_req.menu,
item: room_password_req.item, item: room_password_req.item,
}; };
handler::room::join_room(id, menuselect, &mut block.client_location, &mut self.clients, &mut self.item_state, &mut block.rooms).await?
handler::room::join_room(id, menuselect, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms).await?
} }
else { else {
vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Incorrect password".into())))] vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Incorrect password".into())))]
} }
/*
if room_password_req.password == block.rooms[room_password_req.item as usize]
.read()
.await
.as_ref()
.ok_or(ShipError::InvalidRoom(room_password_req.item))?
.password {
let menuselect = MenuSelect {
menu: room_password_req.menu,
item: room_password_req.item,
};
handler::room::join_room(id, &menuselect, &mut block.client_location, &mut self.clients, &mut self.item_state, &mut block.rooms).await?
}
else {
Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Incorrect password".into())))].into_iter())
}
*/
}, },
RecvShipPacket::CharData(chardata) => { RecvShipPacket::CharData(chardata) => {
let block = self.blocks.from_client(id, &self.clients).await?;
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::lobby::send_player_to_lobby(id, chardata, &mut block.client_location, &self.clients, &self.item_state).await? handler::lobby::send_player_to_lobby(id, chardata, &mut block.client_location, &self.clients, &self.item_state).await?
}, },
RecvShipPacket::Message(msg) => { RecvShipPacket::Message(msg) => {
@ -740,65 +653,65 @@ impl<EG: EntityGateway + Clone> ServerState for ShipServerState<EG> {
self.direct_message(id, msg).await? self.direct_message(id, msg).await?
}, },
RecvShipPacket::PlayerChat(msg) => { RecvShipPacket::PlayerChat(msg) => {
let block = self.blocks.from_client(id, &self.clients).await?;
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::communication::player_chat(id, msg, &block.client_location, &self.clients).await? handler::communication::player_chat(id, msg, &block.client_location, &self.clients).await?
}, },
RecvShipPacket::CreateRoom(create_room) => { RecvShipPacket::CreateRoom(create_room) => {
let block = self.blocks.from_client(id, &self.clients).await?;
handler::room::create_room(id, create_room, &mut block.client_location, &mut self.clients, &mut self.item_state, &mut block.rooms).await?
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::room::create_room(id, create_room, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms).await?
}, },
RecvShipPacket::RoomNameRequest(_req) => { RecvShipPacket::RoomNameRequest(_req) => {
let block = self.blocks.from_client(id, &self.clients).await?;
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::room::room_name_request(id, &block.client_location, &block.rooms).await? handler::room::room_name_request(id, &block.client_location, &block.rooms).await?
}, },
RecvShipPacket::UpdateConfig(pkt) => { RecvShipPacket::UpdateConfig(pkt) => {
handler::settings::update_config(id, pkt, &mut self.clients, &mut self.entity_gateway).await?
handler::settings::update_config(id, pkt, &self.clients, &mut self.entity_gateway).await?
}, },
RecvShipPacket::ViewInfoboardRequest(_pkt) => { RecvShipPacket::ViewInfoboardRequest(_pkt) => {
let block = self.blocks.from_client(id, &self.clients).await?;
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::communication::request_infoboard(id, &block.client_location, &self.clients).await? handler::communication::request_infoboard(id, &block.client_location, &self.clients).await?
}, },
RecvShipPacket::WriteInfoboard(pkt) => { RecvShipPacket::WriteInfoboard(pkt) => {
handler::communication::write_infoboard(id, pkt, &self.clients, &mut self.entity_gateway).await? handler::communication::write_infoboard(id, pkt, &self.clients, &mut self.entity_gateway).await?
}, },
RecvShipPacket::RoomListRequest(_req) => { RecvShipPacket::RoomListRequest(_req) => {
let block = self.blocks.from_client(id, &self.clients).await?;
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::room::request_room_list(id, &block.client_location, &block.rooms).await handler::room::request_room_list(id, &block.client_location, &block.rooms).await
}, },
RecvShipPacket::Like62ButCooler(cool62) => { RecvShipPacket::Like62ButCooler(cool62) => {
let block = self.blocks.from_client(id, &self.clients).await?;
handler::room::cool_62(id, cool62, &block.client_location).await
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::room::cool_62(id, cool62, &block.client_location).await?
}, },
RecvShipPacket::ClientCharacterData(_) => { RecvShipPacket::ClientCharacterData(_) => {
// TOOD: validate this in some way? // TOOD: validate this in some way?
Vec::new() Vec::new()
}, },
RecvShipPacket::DoneBursting(_) => { RecvShipPacket::DoneBursting(_) => {
let block = self.blocks.from_client(id, &self.clients).await?;
handler::room::done_bursting(id, &block.client_location, &mut block.rooms).await?
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::room::done_bursting(id, &block.client_location, &block.rooms).await?
}, },
RecvShipPacket::DoneBursting2(_) => { RecvShipPacket::DoneBursting2(_) => {
let block = self.blocks.from_client(id, &self.clients).await?;
handler::room::done_bursting(id, &block.client_location, &mut block.rooms).await?
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::room::done_bursting(id, &block.client_location, &block.rooms).await?
}, },
RecvShipPacket::LobbySelect(pkt) => { RecvShipPacket::LobbySelect(pkt) => {
let block = self.blocks.from_client(id, &self.clients).await?;
handler::lobby::change_lobby(id, pkt.lobby, &mut block.client_location, &self.clients, &mut self.item_state, &mut block.rooms, &mut self.entity_gateway).await?
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::lobby::change_lobby(id, pkt.lobby, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, &mut self.entity_gateway).await?
}, },
RecvShipPacket::RequestQuestList(rql) => { RecvShipPacket::RequestQuestList(rql) => {
let block = self.blocks.from_client(id, &self.clients).await?;
handler::quest::send_quest_category_list(id, rql, &block.client_location, &mut block.rooms).await?
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::quest::send_quest_category_list(id, rql, &block.client_location, &block.rooms).await?
}, },
RecvShipPacket::QuestFileRequest(quest_file_request) => { RecvShipPacket::QuestFileRequest(quest_file_request) => {
let block = self.blocks.from_client(id, &self.clients).await?;
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::quest::quest_file_request(id, quest_file_request, &block.client_location, &mut block.rooms).await? handler::quest::quest_file_request(id, quest_file_request, &block.client_location, &mut block.rooms).await?
}, },
RecvShipPacket::QuestChunkAck(quest_chunk_ack) => { RecvShipPacket::QuestChunkAck(quest_chunk_ack) => {
let block = self.blocks.from_client(id, &self.clients).await?;
handler::quest::quest_chunk_ack(id, quest_chunk_ack, &block.client_location, &mut block.rooms).await?
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::quest::quest_chunk_ack(id, quest_chunk_ack, &block.client_location, &block.rooms).await?
}, },
RecvShipPacket::DoneLoadingQuest(_) => { RecvShipPacket::DoneLoadingQuest(_) => {
let block = self.blocks.from_client(id, &self.clients).await?;
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::quest::done_loading_quest(id, &self.clients, &block.client_location).await? handler::quest::done_loading_quest(id, &self.clients, &block.client_location).await?
}, },
RecvShipPacket::FullCharacterData(_full_character_data) => { RecvShipPacket::FullCharacterData(_full_character_data) => {
@ -814,11 +727,11 @@ impl<EG: EntityGateway + Clone> ServerState for ShipServerState<EG> {
handler::ship::block_list(id, &self.name, self.blocks.0.len()) handler::ship::block_list(id, &self.name, self.blocks.0.len())
}, },
RecvShipPacket::ItemsToTrade(items_to_trade) => { RecvShipPacket::ItemsToTrade(items_to_trade) => {
let block = self.blocks.from_client(id, &self.clients).await?;
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::trade::items_to_trade(id, items_to_trade, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? handler::trade::items_to_trade(id, items_to_trade, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await?
}, },
RecvShipPacket::TradeConfirmed(_) => { RecvShipPacket::TradeConfirmed(_) => {
let block = self.blocks.from_client(id, &self.clients).await?;
let block = self.blocks.get_from_client(id, &self.clients).await?;
handler::trade::trade_confirmed(id, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await? handler::trade::trade_confirmed(id, &mut self.entity_gateway, &block.client_location, &self.clients, &mut self.item_state, &mut self.trades).await?
}, },
RecvShipPacket::KeyboardConfig(keyboard_config) => { RecvShipPacket::KeyboardConfig(keyboard_config) => {
@ -832,7 +745,7 @@ impl<EG: EntityGateway + Clone> ServerState for ShipServerState<EG> {
async fn on_disconnect(&mut self, id: ClientId) -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> { async fn on_disconnect(&mut self, id: ClientId) -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> {
//let client = self.clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; //let client = self.clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
let block = self.blocks.from_client(id, &self.clients).await?;
let block = self.blocks.get_from_client(id, &self.clients).await?;
let area_client = block.client_location.get_local_client(id).await?; let area_client = block.client_location.get_local_client(id).await?;
let neighbors = block.client_location.get_client_neighbors(id).await?; let neighbors = block.client_location.get_client_neighbors(id).await?;
@ -886,7 +799,7 @@ impl<EG: EntityGateway + Clone> InterserverActor for ShipServerState<EG> {
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![ 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,
@ -896,7 +809,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::RecvMessage) -> Result<Vec<(ServerId, Self::SendMessage)>, Self::Error> {
match msg { match msg {
LoginMessage::SendMail{..} => { LoginMessage::SendMail{..} => {
Ok(Vec::new()) Ok(Vec::new())

2
src/ship/shops/armor.rs

@ -78,7 +78,7 @@ impl ShopItem for ArmorShopItem {
armor: frame.armor, armor: frame.armor,
dfp: 0, dfp: 0,
evp: 0, evp: 0,
slots: frame.slots as u8,
slots: frame.slots,
}) })
}, },
ArmorShopItem::Barrier(barrier) => { ArmorShopItem::Barrier(barrier) => {

6
tests/test_exp_gain.rs

@ -49,7 +49,7 @@ async fn test_character_gains_exp() {
ship.clients.with(ClientId(1), |client| Box::pin(async move { ship.clients.with(ClientId(1), |client| Box::pin(async move {
assert!(exp == client.character.exp); assert!(exp == client.character.exp);
})).await;
})).await.unwrap();
} }
#[async_std::test] #[async_std::test]
@ -133,9 +133,9 @@ async fn test_character_levels_up_multiple_times() {
assert!(matches!(levelup_pkt[1].1, SendShipPacket::Message(Message {msg: GameMessage::PlayerLevelUp(PlayerLevelUp {lvl: 8, ..})}))); assert!(matches!(levelup_pkt[1].1, SendShipPacket::Message(Message {msg: GameMessage::PlayerLevelUp(PlayerLevelUp {lvl: 8, ..})})));
let c1 = ship.clients.with(ClientId(1), |client| Box::pin(async move {
ship.clients.with(ClientId(1), |client| Box::pin(async move {
assert!(exp == client.character.exp); assert!(exp == client.character.exp);
})).await;
})).await.unwrap();
} }
#[async_std::test] #[async_std::test]

Loading…
Cancel
Save