From 43579f7058f46c1a87d6ad45a29467c73fccf1ec Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 28 Jan 2023 00:56:31 -0700 Subject: [PATCH 01/30] fix postgres stuff to get to a game --- Cargo.lock | 2 + src/entity/gateway/entitygateway.rs | 3 +- .../postgres/migrations/V0004__meseta.sql | 9 ++-- .../postgres/migrations/V0005__trade.sql | 4 +- src/entity/gateway/postgres/models.rs | 8 ++-- src/entity/gateway/postgres/postgres.rs | 44 +++++++++++++------ src/lib.rs | 1 - src/login/character.rs | 12 +++-- src/login/login.rs | 2 +- src/ship/ship.rs | 2 + 10 files changed, 57 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f343af7..e11484a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1040,6 +1040,7 @@ checksum = "739e9d7726dc32173fed2d69d17eef3c54682169e4e20ff1d0a45dcd37063cef" [[package]] name = "libpso" version = "0.1.0" +source = "git+http://git.sharnoth.com/jake/libpso#5051514fb1d3b39a7eb6ff97b624a9ceebd93e40" dependencies = [ "chrono", "psopacket", @@ -1398,6 +1399,7 @@ dependencies = [ [[package]] name = "psopacket" version = "1.0.0" +source = "git+http://git.sharnoth.com/jake/libpso#5051514fb1d3b39a7eb6ff97b624a9ceebd93e40" dependencies = [ "proc-macro2", "quote", diff --git a/src/entity/gateway/entitygateway.rs b/src/entity/gateway/entitygateway.rs index 75518e1..7ab6903 100644 --- a/src/entity/gateway/entitygateway.rs +++ b/src/entity/gateway/entitygateway.rs @@ -10,9 +10,10 @@ use crate::entity::item::*; // TODO: better granularity? //#[derive(Error, Debug)] #[derive(Error, Debug)] -#[error("")] pub enum GatewayError { + #[error("unknown error")] Error, + #[error("postgres error {0}")] PgError(#[from] sqlx::Error) } diff --git a/src/entity/gateway/postgres/migrations/V0004__meseta.sql b/src/entity/gateway/postgres/migrations/V0004__meseta.sql index 97f6b2e..efca1db 100644 --- a/src/entity/gateway/postgres/migrations/V0004__meseta.sql +++ b/src/entity/gateway/postgres/migrations/V0004__meseta.sql @@ -1,10 +1,10 @@ create table character_meseta ( - pchar integer references character (id) not null unique, - meseta integer not null, + pchar integer references player_character (id) not null unique, + meseta integer not null ); create table bank_meseta ( - pchar integer references character (id) not null, + pchar integer references player_character (id) not null, bank varchar(128) not null, meseta integer not null, unique (pchar, bank) @@ -12,4 +12,5 @@ create table bank_meseta ( alter table player_character - drop column meseta, bank_meseta; + drop column meseta, + drop column bank_meseta; diff --git a/src/entity/gateway/postgres/migrations/V0005__trade.sql b/src/entity/gateway/postgres/migrations/V0005__trade.sql index 16d3b84..4043c6b 100644 --- a/src/entity/gateway/postgres/migrations/V0005__trade.sql +++ b/src/entity/gateway/postgres/migrations/V0005__trade.sql @@ -1,5 +1,5 @@ create table trades ( id serial primary key not null, - character1 integer references character (id) not null, - character2 integer references character (id) not null, + character1 integer references player_character (id) not null, + character2 integer references player_character (id) not null ); diff --git a/src/entity/gateway/postgres/models.rs b/src/entity/gateway/postgres/models.rs index c7a378b..5350964 100644 --- a/src/entity/gateway/postgres/models.rs +++ b/src/entity/gateway/postgres/models.rs @@ -49,8 +49,8 @@ pub struct PgUserSettings { id: i32, user_account: i32, blocked_users: Vec, //[u32; 0x1E], - keyboard_config: Vec, //[u8; 0x16C], - gamepad_config: Vec, //[u8; 0x38], + key_config: Vec, //[u8; 0x16C], + joystick_config: Vec, //[u8; 0x38], option_flags: i32, shortcuts: Vec, //[u8; 0xA40], symbol_chats: Vec, //[u8; 0x4E0], @@ -64,8 +64,8 @@ impl From for UserSettingsEntity { user_id: UserAccountId(other.user_account as u32), settings: settings::UserSettings { blocked_users: vec_to_array(other.blocked_users.chunks(4).map(|b| u32::from_le_bytes([b[0], b[1], b[2], b[3]])).collect()), - keyboard_config: vec_to_array(other.keyboard_config), - gamepad_config: vec_to_array(other.gamepad_config), + keyboard_config: vec_to_array(other.key_config), + gamepad_config: vec_to_array(other.joystick_config), option_flags: other.option_flags as u32, shortcuts: vec_to_array(other.shortcuts), symbol_chats: vec_to_array(other.symbol_chats), diff --git a/src/entity/gateway/postgres/postgres.rs b/src/entity/gateway/postgres/postgres.rs index d6ab8ee..a3d4f14 100644 --- a/src/entity/gateway/postgres/postgres.rs +++ b/src/entity/gateway/postgres/postgres.rs @@ -224,10 +224,21 @@ async fn save_user_settings(conn: &mut sqlx::PgConnection, settings: &UserSettin async fn create_character(conn: &mut sqlx::PgConnection, char: NewCharacterEntity) -> Result { let q = r#"insert into player_character - (user_account, slot, name, exp, class, section_id, costume, skin, face, head, hair, hair_r, hair_g, hair_b, prop_x, prop_y, techs, - config, infoboard, guildcard, power, mind, def, evade, luck, hp, tp, tech_menu, option_flags) + (user_account, slot, name, exp, class, + section_id, costume, skin, face, head, + hair, hair_r, hair_g, hair_b, prop_x, + prop_y, techs, config, infoboard, guildcard, + power, mind, def, evade, luck, + hp, tp, tech_menu, option_flags, keyboard_config, + gamepad_config, playtime) values - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31) + ($1, $2, $3, $4, $5, + $6, $7, $8, $9, $10, + $11, $12, $13, $14, $15, + $16, $17, $18, $19, $20, + $21, $22, $23, $24, $25, + $26, $27, $28, $29, $30, + $31, $32) returning *;"#; let character = sqlx::query_as::<_, PgCharacter>(q) .bind(char.user_id.0) @@ -259,6 +270,9 @@ async fn create_character(conn: &mut sqlx::PgConnection, char: NewCharacterEntit .bind(char.materials.tp as i16) .bind(char.tech_menu.tech_menu.to_vec()) .bind(char.option_flags as i32) + .bind(&char.keyboard_config.keyboard_config.to_vec()) + .bind(&char.gamepad_config.gamepad_config.to_vec()) + .bind(0) .fetch_one(conn).await?; Ok(character.into()) @@ -284,8 +298,8 @@ async fn save_character(conn: &mut sqlx::PgConnection, char: &CharacterEntity) - let q = r#"update player_character set user_account=$1, slot=$2, name=$3, exp=$4, class=$5, section_id=$6, costume=$7, skin=$8, face=$9, head=$10, hair=$11, hair_r=$12, hair_g=$13, hair_b=$14, prop_x=$15, prop_y=$16, techs=$17, config=$18, infoboard=$19, guildcard=$20, power=$21, mind=$22, def=$23, - evade=$24, luck=$25, hp=$26, tp=$27, tech_menu=$28, option_flags=$29, playtime=$30 - where id=$31;"#; + evade=$24, luck=$25, hp=$26, tp=$27, tech_menu=$28, option_flags=$29, keyboard_config=$30, gamepad_config=$31, playtime=$32, + where id=$33;"#; sqlx::query(q) .bind(char.user_id.0) // $1 .bind(char.slot as i16) // $2 @@ -316,8 +330,10 @@ async fn save_character(conn: &mut sqlx::PgConnection, char: &CharacterEntity) - .bind(char.materials.tp as i16) // $27 .bind(char.tech_menu.tech_menu.to_vec()) // $28 .bind(char.option_flags as i32) // $29 - .bind(char.playtime as i32) // $20 - .bind(char.id.0 as i32) // $31 + .bind(&char.keyboard_config.keyboard_config.to_vec()) // $30 + .bind(&char.gamepad_config.gamepad_config.to_vec()) // $31 + .bind(char.playtime as i32) // $32 + .bind(char.id.0 as i32) // $33 .execute(conn).await?; Ok(()) } @@ -530,7 +546,7 @@ async fn set_character_equips(conn: &mut sqlx::PgConnection, char_id: &Character async fn set_character_meseta(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, meseta: Meseta) -> Result<(), GatewayError> { - sqlx::query("insert into character_meseta values ($1, $2) on conflict (pchar) do update set items = $2") + sqlx::query("insert into character_meseta values ($1, $2) on conflict (pchar) do update set meseta = $2") .bind(char_id.0) .bind(meseta.0 as i32) .execute(conn) @@ -542,7 +558,7 @@ async fn get_character_meseta(conn: &mut sqlx::PgConnection, char_id: &Character { #[derive(sqlx::FromRow)] struct PgMeseta(i32); - let meseta = sqlx::query_as::<_, PgMeseta>(r#"select meseta from character_meseta where id = $1"#) + let meseta = sqlx::query_as::<_, PgMeseta>(r#"select meseta from character_meseta where pchar = $1"#) .bind(char_id.0) .fetch_one(conn) .await?; @@ -551,10 +567,10 @@ async fn get_character_meseta(conn: &mut sqlx::PgConnection, char_id: &Character async fn set_bank_meseta(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, bank: &BankName, meseta: Meseta) -> Result<(), GatewayError> { - sqlx::query("insert into bank_meseta values ($1, $2, $3) on conflict (pchar, bank) do update set items = $2") + sqlx::query("insert into bank_meseta values ($1, $2, $3) on conflict (pchar, bank) do update set meseta = $3") .bind(char_id.0) - .bind(meseta.0 as i32) .bind(bank.0.clone()) + .bind(meseta.0 as i32) .execute(conn) .await?; Ok(()) @@ -564,7 +580,7 @@ async fn get_bank_meseta(conn: &mut sqlx::PgConnection, char_id: &CharacterEntit { #[derive(sqlx::FromRow)] struct PgMeseta(i32); - let meseta = sqlx::query_as::<_, PgMeseta>(r#"select meseta from character_meseta where id = $1 and bank = $2"#) + let meseta = sqlx::query_as::<_, PgMeseta>(r#"select meseta from bank_meseta where pchar = $1 and bank = $2"#) .bind(char_id.0) .bind(bank.0.clone()) .fetch_one(conn) @@ -584,10 +600,10 @@ async fn create_trade(conn: &mut sqlx::PgConnection, char_id1: &CharacterEntityI async fn set_character_playtime(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError> { - sqlx::query_as::<_, PgTradeEntity>(r#"update player_character set playtime=$2 where id=$1;"#) + sqlx::query(r#"update player_character set playtime=$2 where id=$1;"#) .bind(char_id.0) .bind(playtime) - .fetch_one(conn) + .execute(conn) .await?; Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 176a9fe..e9edf0e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,6 @@ #![feature(drain_filter)] #![feature(try_blocks)] #![feature(once_cell)] -#![feature(pin_macro)] #![feature(test)] extern crate test; diff --git a/src/login/character.rs b/src/login/character.rs index b6e28ab..928b4b2 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -38,13 +38,18 @@ pub const CHARACTER_PORT: u16 = 12001; pub const SHIP_MENU_ID: u32 = 1; #[derive(thiserror::Error, Debug)] -#[error("")] pub enum CharacterError { + #[error("invalid menu selection {0} {1}")] InvalidMenuSelection(u32, u32), + #[error("client not found {0}")] ClientNotFound(ClientId), - CouldNotLoadSettings, + #[error("could not load settings {0}")] + CouldNotLoadSettings(GatewayError), + #[error("could not load characters")] CouldNotLoadCharacters, + #[error("could not load guildcard")] CouldNotLoadGuildcard, + #[error("gateway error {0}")] GatewayError(#[from] GatewayError), } @@ -206,6 +211,7 @@ async fn new_character(entity_gateway: &mut EG, user: let character = entity_gateway.create_character(character).await?; entity_gateway.set_character_meseta(&character.id, Meseta(300)).await?; + entity_gateway.set_bank_meseta(&character.id, &BankName("".into()), Meseta(300)).await?; let new_weapon = match character.char_class { CharacterClass::HUmar | CharacterClass::HUnewearl | CharacterClass::HUcast | CharacterClass::HUcaseal => item::weapon::WeaponType::Saber, @@ -385,7 +391,7 @@ impl CharacterServerState { Ok(settings) => settings, Err(_) => { let user_settings = NewUserSettingsEntity::new(user.id); - self.entity_gateway.create_user_settings(user_settings).await.map_err(|_| CharacterError::CouldNotLoadSettings)? + self.entity_gateway.create_user_settings(user_settings).await.map_err(|err| CharacterError::CouldNotLoadSettings(err))? } }; diff --git a/src/login/login.rs b/src/login/login.rs index e37b0ff..bce909a 100644 --- a/src/login/login.rs +++ b/src/login/login.rs @@ -21,8 +21,8 @@ pub const LOGIN_PORT: u16 = 12000; pub const COMMUNICATION_PORT: u16 = 12123; #[derive(thiserror::Error, Debug)] -#[error("")] pub enum LoginError { + #[error("dberror")] DbError } diff --git a/src/ship/ship.rs b/src/ship/ship.rs index a71cc14..88cb2a4 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -834,6 +834,8 @@ impl ServerState for ShipServerState { self.item_state.remove_character_from_room(&client.character).await } + block.client_location.remove_client_from_area(id).await?; + Ok(neighbors.into_iter().map(|n| { (n.client, pkt.clone()) }).collect()) -- 2.36.0 From a2686e2be8ea28696a01cbb2b9f9fbf81a5c21fa Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 28 Jan 2023 20:12:20 -0700 Subject: [PATCH 02/30] anyhow --- Cargo.lock | 4 +- Cargo.toml | 2 +- src/common/mainloop/client.rs | 10 +-- src/entity/gateway/entitygateway.rs | 5 +- src/entity/gateway/inmemory.rs | 5 +- src/entity/gateway/postgres/postgres.rs | 13 ++-- src/lib.rs | 2 + src/ship/client.rs | 6 +- src/ship/items/actions.rs | 87 ++++++++++++----------- src/ship/items/apply_item.rs | 33 +++++---- src/ship/items/state.rs | 30 ++++---- src/ship/items/tasks.rs | 40 ++++++----- src/ship/location.rs | 26 +++++-- src/ship/packet/builder/lobby.rs | 11 ++- src/ship/packet/builder/room.rs | 7 +- src/ship/packet/handler/auth.rs | 2 +- src/ship/packet/handler/communication.rs | 10 +-- src/ship/packet/handler/direct_message.rs | 50 ++++++------- src/ship/packet/handler/lobby.rs | 12 ++-- src/ship/packet/handler/message.rs | 34 ++++----- src/ship/packet/handler/quest.rs | 36 +++++----- src/ship/packet/handler/room.rs | 14 ++-- src/ship/packet/handler/settings.rs | 8 +-- src/ship/packet/handler/trade.rs | 26 +++---- src/ship/room.rs | 10 +-- src/ship/ship.rs | 8 ++- 26 files changed, 258 insertions(+), 233 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e11484a..fcb706f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.57" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" dependencies = [ "backtrace", ] diff --git a/Cargo.toml b/Cargo.toml index e746d70..d62e110 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,4 +32,4 @@ refinery = { version = "0.5.0", features = ["postgres"] } sqlx = { version = "0.5.10", features = ["runtime-async-std-native-tls", "postgres", "json", "chrono"] } strum = "0.19.5" strum_macros = "0.19" -anyhow = { version = "1.0.47", features = ["backtrace"] } +anyhow = { version = "1.0.68", features = ["backtrace"] } diff --git a/src/common/mainloop/client.rs b/src/common/mainloop/client.rs index 1d24600..bca79d2 100644 --- a/src/common/mainloop/client.rs +++ b/src/common/mainloop/client.rs @@ -4,7 +4,7 @@ use async_std::channel; use async_std::io::prelude::{ReadExt, WriteExt}; use async_std::sync::{Arc, RwLock}; use futures::future::Future; -use log::{trace, info, warn}; +use log::{trace, info, warn, error}; use libpso::crypto::{PSOCipher, NullCipher, CipherError}; use libpso::PacketParseError; @@ -132,7 +132,7 @@ where match pkt_receiver.recv_pkts::().await { Ok(pkts) => { for pkt in pkts { - info!("[recv from {:?}] {:#?}", client_id, pkt); + trace!("[recv from {:?}] {:#?}", client_id, pkt); match state.handle(client_id, pkt).await { Ok(response) => { for resp in response { @@ -147,7 +147,7 @@ where } }, Err(err) => { - warn!("[client recv {:?}] error {:?} ", client_id, err); + error!("[client recv {:?}] error {:?} ", client_id, err); } } } @@ -173,7 +173,7 @@ where break; } _ => { - warn!("[client {:?} recv error] {:?}", client_id, err); + error!("[client {:?} recv error] {:?}", client_id, err); } } } @@ -206,7 +206,7 @@ where Ok(pkt) => { info!("[send to {:?}] {:#?}", client_id, pkt); if let Err(err) = send_pkt(&mut socket, &mut cipher, &pkt).await { - warn!("error sending pkt {:#?} to {:?} {:?}", pkt, client_id, err); + error!("error sending pkt {:#?} to {:?} {:?}", pkt, client_id, err); } }, Err(err) => { diff --git a/src/entity/gateway/entitygateway.rs b/src/entity/gateway/entitygateway.rs index 7ab6903..c9cedc0 100644 --- a/src/entity/gateway/entitygateway.rs +++ b/src/entity/gateway/entitygateway.rs @@ -22,12 +22,11 @@ pub enum GatewayError { pub trait EntityGateway: Send + Sync { type Transaction: EntityGatewayTransaction + Clone; - async fn with_transaction<'a, F, Fut, R, E>(&'a mut self, _func: F) -> Result + async fn with_transaction<'a, F, Fut, R>(&'a mut self, _func: F) -> Result where - Fut: Future> + Send + 'a, + Fut: Future> + Send + 'a, F: FnOnce(Self::Transaction) -> Fut + Send, R: Send, - E: From, Self: Sized { unimplemented!(); diff --git a/src/entity/gateway/inmemory.rs b/src/entity/gateway/inmemory.rs index a813a93..9e4a9a0 100644 --- a/src/entity/gateway/inmemory.rs +++ b/src/entity/gateway/inmemory.rs @@ -304,12 +304,11 @@ fn apply_modifiers(items: &BTreeMap, impl EntityGateway for InMemoryGateway { type Transaction = InMemoryGatewayTransaction; - async fn with_transaction<'a, F, Fut, R, E>(&'a mut self, func: F) -> Result + async fn with_transaction<'a, F, Fut, R>(&'a mut self, func: F) -> Result where - Fut: Future> + Send + 'a, + Fut: Future> + Send + 'a, F: FnOnce(Self::Transaction) -> Fut + Send, R: Send, - E: From, { let users = self.users.lock().await.clone(); let user_settings = self.user_settings.lock().await.clone(); diff --git a/src/entity/gateway/postgres/postgres.rs b/src/entity/gateway/postgres/postgres.rs index a3d4f14..0016487 100644 --- a/src/entity/gateway/postgres/postgres.rs +++ b/src/entity/gateway/postgres/postgres.rs @@ -298,7 +298,7 @@ async fn save_character(conn: &mut sqlx::PgConnection, char: &CharacterEntity) - let q = r#"update player_character set user_account=$1, slot=$2, name=$3, exp=$4, class=$5, section_id=$6, costume=$7, skin=$8, face=$9, head=$10, hair=$11, hair_r=$12, hair_g=$13, hair_b=$14, prop_x=$15, prop_y=$16, techs=$17, config=$18, infoboard=$19, guildcard=$20, power=$21, mind=$22, def=$23, - evade=$24, luck=$25, hp=$26, tp=$27, tech_menu=$28, option_flags=$29, keyboard_config=$30, gamepad_config=$31, playtime=$32, + evade=$24, luck=$25, hp=$26, tp=$27, tech_menu=$28, option_flags=$29, keyboard_config=$30, gamepad_config=$31, playtime=$32 where id=$33;"#; sqlx::query(q) .bind(char.user_id.0) // $1 @@ -612,18 +612,17 @@ async fn set_character_playtime(conn: &mut sqlx::PgConnection, char_id: &Charact impl<'t> EntityGateway for PostgresGateway<'t> { type Transaction = PostgresTransaction<'t>; - async fn with_transaction<'a, F, Fut, R, E>(&'a mut self, func: F) -> Result + async fn with_transaction<'a, F, Fut, R>(&'a mut self, func: F) -> Result where - Fut: Future> + Send + 'a, + Fut: Future> + Send + 'a, F: FnOnce(Self::Transaction) -> Fut + Send, R: Send, - E: From, { let transaction = PostgresTransaction { - pgtransaction: Arc::new(Mutex::new(self.pool.begin().await.map_err(|_| ()).unwrap())) + pgtransaction: Arc::new(Mutex::new(self.pool.begin().await?)) }; - let (transaction, result) = func(transaction).await.map_err(|_| ()).unwrap(); - transaction.commit().await.map_err(|_| ()).unwrap(); + let (transaction, result) = func(transaction).await?; + transaction.commit().await?; Ok(result) } diff --git a/src/lib.rs b/src/lib.rs index e9edf0e..2c1ab47 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,8 @@ #![feature(try_blocks)] #![feature(once_cell)] #![feature(test)] +#![feature(error_generic_member_access)] +#![feature(provide_any)] extern crate test; diff --git a/src/ship/client.rs b/src/ship/client.rs index 795c880..5495309 100644 --- a/src/ship/client.rs +++ b/src/ship/client.rs @@ -36,7 +36,7 @@ impl Clients { .into_inner()) } - pub async fn with<'a, T, F>(&'a self, client_id: ClientId, func: F) -> Result + pub async fn with<'a, T, F>(&'a self, client_id: ClientId, func: F) -> Result where T: Send, F: for<'b> FnOnce(&'b ClientState) -> BoxFuture<'b, T> + Send + 'a, @@ -53,7 +53,7 @@ impl Clients { Ok(func(&client).await) } - pub async fn with_many<'a, T, F, const N: usize>(&'a self, client_ids: [ClientId; N], func: F) -> Result + pub async fn with_many<'a, T, F, const N: usize>(&'a self, client_ids: [ClientId; N], func: F) -> Result where T: Send, F: for<'b> FnOnce([RwLockReadGuard<'b, ClientState>; N]) -> BoxFuture<'b, T> + Send + 'a, @@ -85,7 +85,7 @@ impl Clients { Ok(func(client_states).await) } - pub async fn with_mut<'a, T, F>(&'a self, client_id: ClientId, func: F) -> Result + pub async fn with_mut<'a, T, F>(&'a self, client_id: ClientId, func: F) -> Result where T: Send, F: for<'b> FnOnce(&'b mut ClientState) -> BoxFuture<'b, T> + Send + 'a, diff --git a/src/ship/items/actions.rs b/src/ship/items/actions.rs index c6875ef..f67d149 100644 --- a/src/ship/items/actions.rs +++ b/src/ship/items/actions.rs @@ -6,6 +6,8 @@ use std::future::Future; use std::pin::Pin; use std::iter::IntoIterator; +use log::warn; + use libpso::packet::{ship::Message, messages::GameMessage}; use crate::ship::map::MapArea; use crate::ship::ship::SendShipPacket; @@ -35,7 +37,7 @@ pub(super) fn take_item_from_floor( character_id: CharacterEntityId, item_id: ClientItemId ) -> impl Fn((ItemStateProxy, TR), ()) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway + Send, TR: EntityGatewayTransaction + 'static, @@ -54,7 +56,7 @@ where pub(super) fn add_floor_item_to_inventory( character: &CharacterEntity ) -> impl Fn((ItemStateProxy, TR), FloorItem) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + Clone + 'static, @@ -103,7 +105,7 @@ pub(super) fn take_item_from_inventory( item_id: ClientItemId, amount: u32, ) -> impl Fn((ItemStateProxy, TR), ()) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -127,7 +129,7 @@ pub(super) fn add_inventory_item_to_shared_floor( map_area: MapArea, drop_position: (f32, f32, f32), ) -> impl Fn((ItemStateProxy, TR), InventoryItem) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -160,7 +162,7 @@ pub(super) fn take_meseta_from_inventory( character_id: CharacterEntityId, amount: u32, ) -> impl Fn((ItemStateProxy, TR), ()) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -181,7 +183,7 @@ pub(super) fn add_meseta_to_inventory( character_id: CharacterEntityId, amount: u32 ) -> impl Fn((ItemStateProxy, TR), ()) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -204,7 +206,7 @@ pub(super) fn add_meseta_to_shared_floor( map_area: MapArea, drop_position: (f32, f32) ) -> impl Fn((ItemStateProxy, TR), ()) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -233,7 +235,7 @@ pub(super) fn take_meseta_from_bank( character_id: CharacterEntityId, amount: u32, ) -> impl Fn((ItemStateProxy, TR), ()) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -253,7 +255,7 @@ pub(super) fn add_meseta_from_bank_to_inventory( character_id: CharacterEntityId, amount: u32, ) -> impl Fn((ItemStateProxy, TR), ()) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -274,7 +276,7 @@ pub(super) fn add_meseta_to_bank( character_id: CharacterEntityId, amount: u32, ) -> impl Fn((ItemStateProxy, TR), ()) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -296,7 +298,7 @@ pub(super) fn take_item_from_bank( item_id: ClientItemId, amount: u32, ) -> impl Fn((ItemStateProxy, TR), ()) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -316,7 +318,7 @@ where pub(super) fn add_bank_item_to_inventory( character: &CharacterEntity, ) -> impl Fn((ItemStateProxy, TR), BankItem) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -367,7 +369,7 @@ where pub(super) fn add_inventory_item_to_bank( character_id: CharacterEntityId, ) -> impl Fn((ItemStateProxy, TR), InventoryItem) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -403,7 +405,7 @@ pub(super) fn equip_inventory_item( item_id: ClientItemId, equip_slot: u8, ) -> impl Fn((ItemStateProxy, TR), ()) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -425,7 +427,7 @@ pub(super) fn unequip_inventory_item( character_id: CharacterEntityId, item_id: ClientItemId, ) -> impl Fn((ItemStateProxy, TR), ()) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -448,7 +450,7 @@ pub(super) fn sort_inventory_items( character_id: CharacterEntityId, item_ids: Vec, ) -> impl Fn((ItemStateProxy, TR), ()) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -470,7 +472,7 @@ where pub(super) fn use_consumed_item( character: &CharacterEntity, ) -> impl Fn((ItemStateProxy, TR), InventoryItem) - -> BoxFuture), ItemStateError>> + -> BoxFuture), anyhow::Error>> where EG: EntityGateway + Clone + 'static, TR: EntityGatewayTransaction + 'static, @@ -497,7 +499,7 @@ pub(super) fn feed_mag_item( character: CharacterEntity, mag_item_id: ClientItemId, ) -> impl Fn((ItemStateProxy, TR), InventoryItem) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -551,7 +553,7 @@ pub(super) fn add_bought_item_to_inventory<'a, EG, TR>( item_id: ClientItemId, amount: u32, ) -> impl Fn((ItemStateProxy, TR), ()) - -> Pin> + Send + 'a>> + -> Pin> + Send + 'a>> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -613,7 +615,7 @@ where pub(super) fn sell_inventory_item( character_id: CharacterEntityId, ) -> impl Fn((ItemStateProxy, TR), InventoryItem) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -643,7 +645,7 @@ async fn iterate_inner<'a, EG, TR, I, O, T, F, FR>( mut input: Vec, func: F, arg: T, -) -> Result<((ItemStateProxy, TR), Vec), ItemStateError> +) -> Result<((ItemStateProxy, TR), Vec), anyhow::Error> where 'a: 'async_recursion, EG: EntityGateway, @@ -653,7 +655,7 @@ where T: Clone + Send + Sync, F: Fn(I) -> FR + Send + Sync + Clone + 'static, FR: Fn((ItemStateProxy, TR), T) - -> BoxFuture> + Send + Sync, + -> BoxFuture> + Send + Sync, { let item = match input.pop() { Some(item) => item, @@ -673,7 +675,7 @@ pub(super) fn iterate( input: Vec, func: F, ) -> impl Fn((ItemStateProxy, TR), T) - -> BoxFuture), ItemStateError>> + -> BoxFuture), anyhow::Error>> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -682,7 +684,7 @@ where T: Send + Clone + 'static + std::fmt::Debug, F: Fn(I) -> FR + Send + Sync + Clone + 'static, FR: Fn((ItemStateProxy, TR), T) - -> BoxFuture> + Send + Sync, + -> BoxFuture> + Send + Sync, T: Clone + Send + Sync, { move |(item_state, transaction), arg| { @@ -701,7 +703,7 @@ async fn foreach_inner<'a, EG, TR, O, T, F, I>( state: (ItemStateProxy, TR), mut input: I, func: Arc, -) -> Result<((ItemStateProxy, TR), Vec), ItemStateError> +) -> Result<((ItemStateProxy, TR), Vec), anyhow::Error> where 'a: 'async_recursion, EG: EntityGateway, @@ -709,7 +711,7 @@ where O: Send, T: Send, F: Fn((ItemStateProxy, TR), T) - -> BoxFuture> + Send + Sync, + -> BoxFuture> + Send + Sync, I: Iterator + Send + Sync + 'static, { let item = match input.next() { @@ -728,14 +730,14 @@ where pub(super) fn foreach( func: F ) -> impl Fn((ItemStateProxy, TR), I) - -> BoxFuture), ItemStateError>> + -> BoxFuture), anyhow::Error>> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, O: Send, T: Send + Clone + 'static + std::fmt::Debug, F: Fn((ItemStateProxy, TR), T) - -> BoxFuture> + Send + Sync + 'static, + -> BoxFuture> + Send + Sync + 'static, T: Send + Sync, I: IntoIterator + Send + Sync + 'static, I::IntoIter: Send + Sync, @@ -754,7 +756,7 @@ where pub(super) fn insert<'a, EG, TR, T>( element: T ) -> impl Fn((ItemStateProxy, TR), ()) - -> Pin> + Send + 'a>> + -> Pin> + Send + 'a>> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -772,12 +774,12 @@ pub(super) fn fork( func1: F1, func2: F2, ) -> impl Fn((ItemStateProxy, TR), T) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, - F1: Fn((ItemStateProxy, TR), T) -> BoxFuture> + Send + Sync + 'static, - F2: Fn((ItemStateProxy, TR), T) -> BoxFuture> + Send + Sync + 'static, + F1: Fn((ItemStateProxy, TR), T) -> BoxFuture> + Send + Sync + 'static, + F2: Fn((ItemStateProxy, TR), T) -> BoxFuture> + Send + Sync + 'static, T: Send + Sync + Clone + 'static, O1: Send, O2: Send, @@ -799,7 +801,7 @@ where pub(super) fn add_item_to_inventory( character: CharacterEntity, ) -> impl Fn((ItemStateProxy, TR), InventoryItem) - -> BoxFuture> + Clone + -> BoxFuture> + Clone where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -829,7 +831,7 @@ pub(super) fn record_trade( character_to: CharacterEntityId, character_from: CharacterEntityId, ) -> impl Fn((ItemStateProxy, TR), Vec) - -> BoxFuture), ItemStateError>> + Clone + -> BoxFuture), anyhow::Error>> + Clone where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -855,7 +857,7 @@ where pub(super) fn assign_new_item_id( ) -> impl Fn((ItemStateProxy, TR), InventoryItem) - -> BoxFuture> + Clone + -> BoxFuture> + Clone where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -873,7 +875,7 @@ pub(super) fn convert_item_drop_to_floor_item( character_id: CharacterEntityId, item_drop: ItemDrop, ) -> impl Fn((ItemStateProxy, TR), ()) - -> BoxFuture> + Clone + -> BoxFuture> + Clone where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -881,6 +883,7 @@ where move |(mut item_state, mut transaction), _| { let item_drop = item_drop.clone(); Box::pin(async move { + warn!("converting item drop to floor item"); enum ItemOrMeseta { Individual(ItemDetail), Stacked(Tool), @@ -993,7 +996,7 @@ where pub(super) fn apply_modifier_to_inventory_item( modifier: ItemModifier, ) -> impl Fn((ItemStateProxy, TR), InventoryItem) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -1006,7 +1009,7 @@ where weapon.apply_modifier(&modifier); transaction.gateway().add_weapon_modifier(entity_id, modifier).await?; }, - _ => return Err(ItemStateError::InvalidModifier) + _ => return Err(ItemStateError::InvalidModifier.into()) } Ok(((item_state, transaction), inventory_item)) @@ -1016,7 +1019,7 @@ where pub(super) fn as_individual_item( ) -> impl Fn((ItemStateProxy, TR), InventoryItem) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -1025,7 +1028,7 @@ where Box::pin(async move { let item = match inventory_item.item { InventoryItemDetail::Individual(individual_item) => individual_item, - _ => return Err(ItemStateError::WrongItemType(inventory_item.item_id)) + _ => return Err(ItemStateError::WrongItemType(inventory_item.item_id).into()) }; Ok(((item_state, transaction), item)) @@ -1038,7 +1041,7 @@ pub(super) fn apply_item_action_packets( character_id: CharacterEntityId, area_client: AreaClient, ) -> impl Fn((ItemStateProxy, TR), ApplyItemAction) - -> BoxFuture), ItemStateError>> + -> BoxFuture), anyhow::Error>> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, @@ -1095,7 +1098,7 @@ where pub(super) fn apply_item_action_character( character: &CharacterEntity ) -> impl Fn((ItemStateProxy, TR), Vec) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, diff --git a/src/ship/items/apply_item.rs b/src/ship/items/apply_item.rs index b78a94b..bd01ecf 100644 --- a/src/ship/items/apply_item.rs +++ b/src/ship/items/apply_item.rs @@ -23,8 +23,8 @@ pub enum ApplyItemError { #[error("gateway error {0}")] GatewayError(#[from] GatewayError), - #[error("itemstate error {0}")] - ItemStateError(Box), + //#[error("itemstate error {0}")] + //ItemStateError(Box), #[error("magcell error {0}")] MagCellError(#[from] MagCellError), @@ -38,49 +38,52 @@ pub enum ApplyItemAction { //RemoveItem, } +/* impl From for ApplyItemError { fn from(other: ItemStateError) -> ApplyItemError { ApplyItemError::ItemStateError(Box::new(other)) } } +*/ + -async fn power_material(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result, ApplyItemError> { +async fn power_material(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result, anyhow::Error> { character.materials.power += 1; entity_gateway.save_character(character).await?; Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) } -async fn mind_material(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result, ApplyItemError> { +async fn mind_material(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result, anyhow::Error> { character.materials.mind += 1; entity_gateway.save_character(character).await.unwrap(); Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) } -async fn evade_material(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result, ApplyItemError> { +async fn evade_material(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result, anyhow::Error> { character.materials.evade += 1; entity_gateway.save_character(character).await.unwrap(); Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) } -async fn def_material(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result, ApplyItemError> { +async fn def_material(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result, anyhow::Error> { character.materials.def += 1; entity_gateway.save_character(character).await.unwrap(); Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) } -async fn luck_material(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result, ApplyItemError> { +async fn luck_material(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result, anyhow::Error> { character.materials.luck += 1; entity_gateway.save_character(character).await.unwrap(); Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) } -async fn hp_material(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result, ApplyItemError> { +async fn hp_material(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result, anyhow::Error> { character.materials.hp += 1; entity_gateway.save_character(character).await.unwrap(); Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) } -async fn tp_material(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result, ApplyItemError> { +async fn tp_material(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result, anyhow::Error> { character.materials.tp += 1; entity_gateway.save_character(character).await.unwrap(); Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) @@ -113,7 +116,7 @@ async fn mag_cell<'a, EG>(item_state: &mut ItemStateProxy, character: &CharacterEntity, cell_entity_id: ItemEntityId, mag_cell_type: MagCell) - -> Result, ApplyItemError> + -> Result, anyhow::Error> where EG: EntityGateway + ?Sized, { @@ -229,7 +232,7 @@ pub async fn liberta_kit(entity_gateway: &mut EG, used_cell: */ -fn jack_o_lantern() -> Result, ApplyItemError> +fn jack_o_lantern() -> Result, anyhow::Error> { let mag_rate = WeightedIndex::new(&[13, 13, 13, 13, 12, 12, 12, 12]).unwrap(); let mag_type = match mag_rate.sample(&mut rand_chacha::ChaChaRng::from_entropy()) { @@ -252,7 +255,7 @@ async fn apply_tool<'a, EG>(item_state: &mut ItemStateProxy, character: &mut CharacterEntity, entity_id: ItemEntityId, tool: ToolType) - -> Result, ApplyItemError> + -> Result, anyhow::Error> where EG: EntityGateway + ?Sized, { @@ -299,7 +302,7 @@ where } ToolType::JackOLantern => jack_o_lantern(), // TODO: rest of these - _ => Err(ApplyItemError::InvalidItem) + _ => Err(ApplyItemError::InvalidItem.into()) } } @@ -309,7 +312,7 @@ pub async fn apply_item<'a, EG>(item_state: &mut ItemStateProxy, entity_gateway: &mut EG, character: &mut CharacterEntity, item: InventoryItem -) -> Result, ApplyItemError> +) -> Result, anyhow::Error> where EG: EntityGateway + ?Sized + Clone + 'static { @@ -317,7 +320,7 @@ where InventoryItemDetail::Individual(individual_item) => { match individual_item.item { ItemDetail::Tool(tool) => apply_tool(item_state, entity_gateway, character, individual_item.entity_id, tool.tool).await, - _ => Err(ApplyItemError::InvalidItem) + _ => Err(ApplyItemError::InvalidItem.into()) } }, InventoryItemDetail::Stacked(stacked_item) => { diff --git a/src/ship/items/state.rs b/src/ship/items/state.rs index 6473f38..44df7f9 100644 --- a/src/ship/items/state.rs +++ b/src/ship/items/state.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use async_std::sync::{Arc, RwLock, Mutex}; use futures::future::join_all; +use anyhow::Context; use crate::entity::gateway::{EntityGateway, GatewayError}; use crate::entity::character::{CharacterEntity, CharacterEntityId}; @@ -55,7 +56,7 @@ pub enum ItemStateError { ItemNotSellable, #[error("could not modify item")] InvalidModifier, - #[error("wrong item type ")] + #[error("wrong item type {0}")] WrongItemType(ClientItemId), } @@ -150,7 +151,7 @@ impl Default for ItemState { } impl ItemState { - pub async fn get_character_inventory(&self, character: &CharacterEntity) -> Result { + pub async fn get_character_inventory(&self, character: &CharacterEntity) -> Result { Ok(self.character_inventory .read() .await @@ -161,7 +162,7 @@ impl ItemState { .clone()) } - pub async fn get_character_bank(&self, character: &CharacterEntity) -> Result { + pub async fn get_character_bank(&self, character: &CharacterEntity) -> Result { Ok(self.character_bank .read() .await @@ -174,20 +175,20 @@ impl ItemState { } impl ItemState { - async fn new_item_id(&mut self) -> Result { + async fn new_item_id(&mut self) -> Result { *self.room_item_id_counter .write() .await += 1; Ok(ClientItemId(*self.room_item_id_counter.read().await)) } - pub async fn load_character(&mut self, entity_gateway: &mut EG, character: &CharacterEntity) -> Result<(), ItemStateError> { + pub async fn load_character(&mut self, entity_gateway: &mut EG, character: &CharacterEntity) -> Result<(), anyhow::Error> { let inventory = entity_gateway.get_character_inventory(&character.id).await?; let bank = entity_gateway.get_character_bank(&character.id, &BankName("".into())).await?; let equipped = entity_gateway.get_character_equips(&character.id).await?; let inventory_items = inventory.items.into_iter() - .map(|item| -> Result { + .map(|item| -> Result { Ok(match item { InventoryItemEntity::Individual(item) => { InventoryItem { @@ -214,7 +215,7 @@ impl ItemState { }, }) }) - .collect::, ItemStateError>>()?; + .collect::, anyhow::Error>>()?; let character_meseta = entity_gateway.get_character_meseta(&character.id).await?; let inventory_state = InventoryState { @@ -259,7 +260,7 @@ impl ItemState { .collect::>()) .await .into_iter() - .collect::, ItemStateError>>()?; + .collect::, anyhow::Error>>()?; let bank_meseta = entity_gateway.get_bank_meseta(&character.id, &BankName("".into())).await?; let bank_state = BankState::new(character.id, BankName("".into()), Bank::new(bank_items), bank_meseta); @@ -334,7 +335,7 @@ impl ItemState { } } - pub async fn get_floor_item(&self, character_id: &CharacterEntityId, item_id: &ClientItemId) -> Result<(FloorItem, FloorType), ItemStateError> { + pub async fn get_floor_item(&self, character_id: &CharacterEntityId, item_id: &ClientItemId) -> Result<(FloorItem, FloorType), anyhow::Error> { let local_floors = self.character_floor .read() .await; @@ -369,6 +370,7 @@ impl ItemState { .map(|item| (item.clone(), FloorType::Shared)) }) .ok_or_else(|| ItemStateError::NoFloorItem(*item_id)) + .with_context(|| format!("character {}\nlocal floors: {:#?}\nshared floors: {:#?}", character_id, local_floors, shared_floors)) } } @@ -421,7 +423,7 @@ impl ItemStateProxy { async fn get_or_clone(master: &Arc>>>, proxy: &Arc>>, key: K, - err: fn(K) -> ItemStateError) -> Result + err: fn(K) -> ItemStateError) -> Result where K: Eq + std::hash::Hash + Copy, V: Clone @@ -451,7 +453,7 @@ impl ItemStateProxy { } } - pub async fn inventory(&mut self, character_id: &CharacterEntityId) -> Result { + pub async fn inventory(&mut self, character_id: &CharacterEntityId) -> Result { get_or_clone(&self.item_state.character_inventory, &self.proxied_state.character_inventory, *character_id, @@ -462,7 +464,7 @@ impl ItemStateProxy { self.proxied_state.character_inventory.lock().await.insert(inventory.character_id, inventory); } - pub async fn bank(&mut self, character_id: &CharacterEntityId) -> Result { + pub async fn bank(&mut self, character_id: &CharacterEntityId) -> Result { get_or_clone(&self.item_state.character_bank, &self.proxied_state.character_bank, *character_id, @@ -473,7 +475,7 @@ impl ItemStateProxy { self.proxied_state.character_bank.lock().await.insert(bank.character_id, bank); } - pub async fn floor(&mut self, character_id: &CharacterEntityId) -> Result { + pub async fn floor(&mut self, character_id: &CharacterEntityId) -> Result { let room_id = *self.item_state.character_room.read().await.get(character_id).unwrap(); Ok(FloorState { character_id: *character_id, @@ -488,7 +490,7 @@ impl ItemStateProxy { self.proxied_state.room_floor.lock().await.insert(room_id, floor.shared); } - pub async fn new_item_id(&mut self) -> Result { + pub async fn new_item_id(&mut self) -> Result { self.item_state.new_item_id().await } } diff --git a/src/ship/items/tasks.rs b/src/ship/items/tasks.rs index a1ab65c..6d2f355 100644 --- a/src/ship/items/tasks.rs +++ b/src/ship/items/tasks.rs @@ -5,7 +5,7 @@ use crate::ship::ship::SendShipPacket; use crate::ship::map::MapArea; use crate::entity::character::{CharacterEntity, CharacterEntityId}; use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction}; -use crate::ship::items::state::{ItemState, ItemStateProxy, ItemStateError, IndividualItemDetail}; +use crate::ship::items::state::{ItemState, ItemStateProxy, IndividualItemDetail}; use crate::ship::items::itemstateaction::{ItemStateAction, ItemAction}; use crate::ship::items::inventory::InventoryItem; use crate::ship::items::floor::FloorItem; @@ -17,12 +17,14 @@ use crate::ship::drops::ItemDrop; use crate::ship::items::actions; +use log::warn; + pub async fn pick_up_item( item_state: &mut ItemState, entity_gateway: &mut EG, character: &CharacterEntity, item_id: &ClientItemId) - -> Result + -> Result where EG: EntityGateway + 'static, EG::Transaction: Clone, @@ -46,7 +48,7 @@ pub async fn drop_item( item_id: &ClientItemId, map_area: MapArea, drop_position: (f32, f32, f32)) - -> Result + -> Result where EG: EntityGateway + 'static, { @@ -70,7 +72,7 @@ pub async fn drop_partial_item<'a, EG>( map_area: MapArea, drop_position: (f32, f32), amount: u32) - -> Result + -> Result where EG: EntityGateway + 'static, { @@ -95,7 +97,7 @@ pub async fn drop_meseta<'a, EG>( map_area: MapArea, drop_position: (f32, f32), amount: u32) - -> Result + -> Result where EG: EntityGateway + 'static, { @@ -117,7 +119,7 @@ pub async fn withdraw_meseta<'a, EG>( entity_gateway: &mut EG, character: &CharacterEntity, amount: u32) - -> Result<(), ItemStateError> + -> Result<(), anyhow::Error> where EG: EntityGateway + 'static, { @@ -139,7 +141,7 @@ pub async fn deposit_meseta<'a, EG>( entity_gateway: &mut EG, character: &CharacterEntity, amount: u32) - -> Result<(), ItemStateError> + -> Result<(), anyhow::Error> where EG: EntityGateway + 'static, { @@ -162,7 +164,7 @@ pub async fn withdraw_item<'a, EG>( character: &CharacterEntity, item_id: &ClientItemId, amount: u32) - -> Result + -> Result where EG: EntityGateway + 'static, { @@ -187,7 +189,7 @@ pub async fn deposit_item<'a, EG> ( character: &CharacterEntity, item_id: &ClientItemId, amount: u32) - -> Result<(), ItemStateError> + -> Result<(), anyhow::Error> where EG: EntityGateway + 'static, { @@ -209,7 +211,7 @@ pub async fn equip_item<'a, EG> ( character: &CharacterEntity, item_id: &ClientItemId, equip_slot: u8, -) -> Result<(), ItemStateError> +) -> Result<(), anyhow::Error> where EG: EntityGateway + 'static, { @@ -230,7 +232,7 @@ pub async fn unequip_item<'a, EG> ( entity_gateway: &mut EG, character: &CharacterEntity, item_id: &ClientItemId, -) -> Result<(), ItemStateError> +) -> Result<(), anyhow::Error> where EG: EntityGateway + 'static, { @@ -251,7 +253,7 @@ pub async fn sort_inventory<'a, EG> ( entity_gateway: &mut EG, character: &CharacterEntity, item_ids: Vec, -) -> Result<(), ItemStateError> +) -> Result<(), anyhow::Error> where EG: EntityGateway + 'static, { @@ -274,7 +276,7 @@ pub async fn use_item<'a, EG> ( area_client: AreaClient, item_id: &ClientItemId, amount: u32, -) -> Result, ItemStateError> +) -> Result, anyhow::Error> where EG: EntityGateway + 'static, { @@ -303,7 +305,7 @@ pub async fn feed_mag<'a, EG> ( character: &CharacterEntity, mag_item_id: &ClientItemId, tool_item_id: &ClientItemId, -) -> Result<(), ItemStateError> +) -> Result<(), anyhow::Error> where EG: EntityGateway + 'static, { @@ -327,7 +329,7 @@ pub async fn buy_shop_item<'a, EG> ( shop_item: &'a (dyn ShopItem + Send + Sync), item_id: ClientItemId, amount: u32, -) -> Result +) -> Result where EG: EntityGateway + 'static, { @@ -353,7 +355,7 @@ pub async fn sell_item<'a, EG> ( character: &CharacterEntity, item_id: ClientItemId, amount: u32, -) -> Result +) -> Result where EG: EntityGateway + 'static, { @@ -373,7 +375,7 @@ pub async fn trade_items<'a, EG> ( entity_gateway: &mut EG, p1: (&AreaClient, &CharacterEntity, &Vec, Meseta), p2: (&AreaClient, &CharacterEntity, &Vec, Meseta)) - -> Result<(Vec, Vec), ItemStateError> + -> Result<(Vec, Vec), anyhow::Error> where EG: EntityGateway + 'static, { @@ -443,7 +445,7 @@ pub async fn take_meseta<'a, EG> ( entity_gateway: &mut EG, character_id: &CharacterEntityId, meseta: Meseta) - -> Result<(), ItemStateError> + -> Result<(), anyhow::Error> where EG: EntityGateway + 'static, { @@ -488,7 +490,7 @@ pub async fn apply_modifier<'a, EG> ( character: &CharacterEntity, item_id: ClientItemId, modifier: ItemModifier) - -> Result + -> Result where EG: EntityGateway + 'static, { diff --git a/src/ship/location.rs b/src/ship/location.rs index b3f16cc..5dc805e 100644 --- a/src/ship/location.rs +++ b/src/ship/location.rs @@ -30,41 +30,50 @@ impl LobbyId { #[derive(Error, Debug, PartialEq, Eq)] -#[error("create room")] pub enum CreateRoomError { + #[error("no open slots")] NoOpenSlots, + #[error("client already in area")] ClientInAreaAlready, + #[error("join error")] JoinError, } #[derive(Error, Debug, PartialEq, Eq)] -#[error("join room")] pub enum JoinRoomError { + #[error("room does not exist")] RoomDoesNotExist, + #[error("room is full")] RoomFull, + #[error("client already in area")] ClientInAreaAlready, } #[derive(Error, Debug, PartialEq, Eq)] -#[error("join lobby")] pub enum JoinLobbyError { + #[error("lobby does not exist")] LobbyDoesNotExist, + #[error("lobby is full")] LobbyFull, + #[error("client already in area")] ClientInAreaAlready, } #[derive(Error, Debug, PartialEq, Eq)] -#[error("get area")] pub enum GetAreaError { + #[error("not in a room")] NotInRoom, + #[error("not in a lobby")] NotInLobby, + #[error("get area: invalid client")] InvalidClient, } #[derive(Error, Debug, PartialEq, Eq)] -#[error("client removal")] pub enum ClientRemovalError { + #[error("client removal: client not in area")] ClientNotInArea, + #[error("client removal: invalid area")] InvalidArea, } @@ -77,17 +86,20 @@ pub enum GetClientsError { } #[derive(Error, Debug, PartialEq, Eq)] -#[error("get neighbor")] pub enum GetNeighborError { + #[error("get neighbor: invalid client")] InvalidClient, + #[error("get neighbor: invalid area")] InvalidArea, } #[derive(Error, Debug, PartialEq, Eq)] -#[error("get leader")] pub enum GetLeaderError { + #[error("get leader: invalid client")] InvalidClient, + #[error("get leader: invalid area")] InvalidArea, + #[error("get leader: client not in area")] NoClientInArea, } diff --git a/src/ship/packet/builder/lobby.rs b/src/ship/packet/builder/lobby.rs index 666d9be..af033ca 100644 --- a/src/ship/packet/builder/lobby.rs +++ b/src/ship/packet/builder/lobby.rs @@ -1,6 +1,6 @@ use libpso::packet::ship::*; use crate::common::serverstate::ClientId; -use crate::ship::ship::{ShipError, Clients, ShipEvent}; +use crate::ship::ship::{Clients, ShipEvent}; use crate::ship::location::{ClientLocation, LobbyId, ClientLocationError}; use crate::ship::packet::builder::{player_info}; use crate::ship::items::state::ItemState; @@ -13,7 +13,7 @@ pub async fn join_lobby(id: ClientId, clients: &Clients, item_state: &ItemState, event: ShipEvent) - -> Result { + -> Result { let lobby_clients = client_location.get_clients_in_lobby(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?; let playerinfo = join_all( @@ -28,9 +28,8 @@ pub async fn join_lobby(id: ClientId, }})) .await .into_iter() - .collect::, ShipError>>()?; + .collect::, anyhow::Error>>()?; - //let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); let client_block = clients.with(id, |client| Box::pin(async move { client.block as u16 })).await?; @@ -54,7 +53,7 @@ pub async fn add_to_lobby(id: ClientId, clients: &Clients, item_state: &ItemState, event: ShipEvent) - -> Result { + -> Result { let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let leader = client_location.get_lobby_leader(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?; clients.with(id, |client| { @@ -77,7 +76,7 @@ pub async fn add_to_lobby(id: ClientId, pub async fn remove_from_lobby(id: ClientId, client_location: &ClientLocation) - -> Result { + -> Result { let prev_area_index = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?.local_client.id(); let prev_area_leader_index = client_location .get_area_leader(client_location diff --git a/src/ship/packet/builder/room.rs b/src/ship/packet/builder/room.rs index b50c7fb..acbd5f7 100644 --- a/src/ship/packet/builder/room.rs +++ b/src/ship/packet/builder/room.rs @@ -15,12 +15,11 @@ pub async fn join_room(id: ClientId, room_id: RoomId, room: &RoomState, event: ShipEvent) - -> Result { + -> Result { let all_clients = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; let players = futures::stream::iter(all_clients.iter()) .enumerate() - .fold::, _, _>(Ok([PlayerHeader::default(); 4]), |acc, (i, c)| async move { - //let header_client = clients.get(&c.client).ok_or(ShipError::ClientNotFound(id))?; + .fold::, _, _>(Ok([PlayerHeader::default(); 4]), |acc, (i, c)| async move { let header_area_client = client_location.get_local_client(id).await.map_err(|err| ShipError::ClientLocationError(err.into()))?; clients.with(c.client, |client| Box::pin(async move { acc.map(|mut a| { @@ -59,7 +58,7 @@ pub async fn add_to_room(_id: ClientId, leader: &AreaClient, item_state: &ItemState, event: ShipEvent) - -> Result { + -> Result { let inventory = item_state.get_character_inventory(&client.character).await?; Ok(AddToRoom { flag: 1, diff --git a/src/ship/packet/handler/auth.rs b/src/ship/packet/handler/auth.rs index ddbfeeb..698de75 100644 --- a/src/ship/packet/handler/auth.rs +++ b/src/ship/packet/handler/auth.rs @@ -16,7 +16,7 @@ pub async fn validate_login(id: ClientId, shipgate_sender: &Option>, ship_name: &str, num_blocks: usize) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway, { diff --git a/src/ship/packet/handler/communication.rs b/src/ship/packet/handler/communication.rs index 0a80304..c0ac3e5 100644 --- a/src/ship/packet/handler/communication.rs +++ b/src/ship/packet/handler/communication.rs @@ -1,6 +1,6 @@ use libpso::packet::ship::*; use crate::common::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, ShipError, Clients}; +use crate::ship::ship::{SendShipPacket, Clients}; use crate::ship::location::{ClientLocation}; use crate::entity::gateway::EntityGateway; @@ -10,7 +10,7 @@ pub async fn player_chat(id: ClientId, msg: PlayerChat, client_location: &ClientLocation, clients: &Clients) - -> Result, ShipError> { + -> Result, anyhow::Error> { let cmsg = clients.with(id, |client| Box::pin(async move { PlayerChat::new(client.user.id.0, msg.message) })).await?; @@ -25,7 +25,7 @@ pub async fn player_chat(id: ClientId, pub async fn request_infoboard(id: ClientId, client_location: &ClientLocation, clients: &Clients) - -> Result, ShipError> { + -> Result, anyhow::Error> { let area_clients = client_location.get_client_neighbors(id).await.unwrap(); let infoboards = join_all( area_clients.iter() @@ -39,7 +39,7 @@ pub async fn request_infoboard(id: ClientId, })) .await .into_iter() - .collect::, ShipError>>()?; + .collect::, anyhow::Error>>()?; Ok(vec![(id, SendShipPacket::ViewInfoboardResponse(ViewInfoboardResponse {response: infoboards}))]) } @@ -47,7 +47,7 @@ pub async fn write_infoboard(id: ClientId, new_infoboard: WriteInfoboard, clients: &Clients, entity_gateway: &mut EG) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index 5c49a53..9b9455d 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -39,13 +39,15 @@ async fn send_to_client(id: ClientId, target: u8, msg: DirectMessage, client_location: &ClientLocation) - -> Vec<(ClientId, SendShipPacket)> { - client_location.get_all_clients_by_client(id).await.unwrap().into_iter() - .filter(move |client| client.local_client.id() == target) - .map(move |client| { - (client.client, SendShipPacket::DirectMessage(msg.clone())) - }) - .collect() + -> Result, anyhow::Error> { + Ok(client_location.get_all_clients_by_client(id) + .await? + .into_iter() + .filter(move |client| client.local_client.id() == target) + .map(move |client| { + (client.client, SendShipPacket::DirectMessage(msg.clone())) + }) + .collect()) } pub async fn guildcard_send(id: ClientId, @@ -53,7 +55,7 @@ pub async fn guildcard_send(id: ClientId, target: u32, client_location: &ClientLocation, clients: &Clients) - -> Result, ShipError> { + -> Result, anyhow::Error> { let msg = clients.with(id, |client| Box::pin(async move { DirectMessage{ flag: target, @@ -72,7 +74,7 @@ pub async fn guildcard_send(id: ClientId, } })).await?; - Ok(send_to_client(id, target as u8, msg, client_location).await) + send_to_client(id, target as u8, msg, client_location).await } pub async fn request_item(id: ClientId, @@ -82,7 +84,7 @@ pub async fn request_item(id: ClientId, clients: &Clients, rooms: &Rooms, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + 'static, { @@ -92,7 +94,7 @@ where })).await??; if monster.dropped_item { - return Err(ShipError::MonsterAlreadyDroppedItem(id, request_item.enemy_id)) + return Err(ShipError::MonsterAlreadyDroppedItem(id, request_item.enemy_id).into()) } let clients_in_area = client_location.get_clients_in_room(room_id).await?; @@ -134,7 +136,7 @@ pub async fn pickup_item(id: ClientId, client_location: &ClientLocation, clients: &Clients, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -193,7 +195,7 @@ pub async fn request_box_item(id: ClientId, clients: &Clients, rooms: &Rooms, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static { @@ -203,7 +205,7 @@ where })).await??; if box_object.dropped_item { - return Err(ShipError::BoxAlreadyDroppedItem(id, box_drop_request.object_id)) + return Err(ShipError::BoxAlreadyDroppedItem(id, box_drop_request.object_id).into()) } let clients_in_area = client_location.get_clients_in_room(room_id).await?; @@ -244,7 +246,7 @@ where pub async fn send_bank_list(id: ClientId, clients: &Clients, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> { let bank = clients.with(id, |client| { let item_state = item_state.clone(); @@ -262,7 +264,7 @@ pub async fn bank_interaction(id: ClientId, client_location: &ClientLocation, clients: &Clients, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -273,7 +275,7 @@ where let mut entity_gateway = entity_gateway.clone(); let mut item_state = item_state.clone(); Box::pin(async move { - Ok::<_, ShipError>(match bank_interaction.action { + Ok::<_, anyhow::Error>(match bank_interaction.action { BANK_ACTION_DEPOSIT => { if bank_interaction.item_id == 0xFFFFFFFF { deposit_meseta(&mut item_state, &mut entity_gateway, &client.character, bank_interaction.meseta_amount).await?; @@ -320,7 +322,7 @@ pub async fn shop_request(id: ClientId, clients: &Clients, rooms: &Rooms, shops: &ItemShops) - -> Result, ShipError> + -> Result, anyhow::Error> { //let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; let room_id = client_location.get_room(id).await?; @@ -397,7 +399,7 @@ pub async fn buy_item(id: ClientId, client_location: &ClientLocation, clients: &Clients, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -422,7 +424,7 @@ where (item, remove) }, _ => { - return Err(ShipError::ShopError) + return Err(ShipError::ShopError.into()) } }; @@ -439,7 +441,7 @@ where _ => {} } } - builder::message::create_withdrawn_inventory_item(area_client, &inventory_item) + Ok::<_, anyhow::Error>(builder::message::create_withdrawn_inventory_item(area_client, &inventory_item)?) })}).await??; let other_clients_in_area = client_location.get_client_neighbors(id).await?; @@ -465,7 +467,7 @@ pub async fn request_tek_item(id: ClientId, entity_gateway: &mut EG, clients: &Clients, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -502,7 +504,7 @@ where }); take_meseta(&mut item_state, &mut entity_gateway, &client.character.id, item::Meseta(100)).await?; - builder::message::tek_preview(ClientItemId(tek_request.item_id), &weapon) + Ok::<_, anyhow::Error>(builder::message::tek_preview(ClientItemId(tek_request.item_id), &weapon)?) })}).await??; @@ -515,7 +517,7 @@ pub async fn accept_tek_item(id: ClientId, client_location: &ClientLocation, clients: &Clients, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { diff --git a/src/ship/packet/handler/lobby.rs b/src/ship/packet/handler/lobby.rs index f0caf23..bfafe86 100644 --- a/src/ship/packet/handler/lobby.rs +++ b/src/ship/packet/handler/lobby.rs @@ -16,7 +16,7 @@ pub async fn block_selected(id: ClientId, pkt: MenuSelect, clients: &Clients, item_state: &ItemState) - -> Result, ShipError> { + -> Result, anyhow::Error> { clients.with_mut(id, |client| { let item_state = item_state.clone(); Box::pin(async move { @@ -57,7 +57,7 @@ pub async fn send_player_to_lobby(id: ClientId, clients: &Clients, item_state: &ItemState, event: ShipEvent) - -> Result, ShipError> { + -> Result, anyhow::Error> { let lobby = client_location.add_client_to_next_available_lobby(id, LobbyId(0)).await.map_err(|_| ShipError::TooManyClients)?; let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_state, event).await?; let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state, event).await?; @@ -77,7 +77,7 @@ pub async fn change_lobby(id: ClientId, rooms: &Rooms, entity_gateway: &mut EG, event: ShipEvent) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -134,7 +134,7 @@ where pub async fn remove_from_lobby(id: ClientId, client_location: &mut ClientLocation) - -> Result, ShipError> { + -> Result, anyhow::Error> { let area_client = client_location.get_local_client(id).await?; let neighbors = client_location.get_client_neighbors(id).await?; let leader = client_location.get_leader_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; @@ -150,7 +150,7 @@ pub async fn get_room_tab_info(id: ClientId, pkt: MenuDetail, client_location: &mut ClientLocation, clients: &Clients) - -> Result, ShipError> { + -> Result, anyhow::Error> { let room_id = RoomId(pkt.item as usize); let clients_in_room = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; let room_info = if clients_in_room.is_empty() { @@ -169,7 +169,7 @@ pub async fn get_room_tab_info(id: ClientId, })).await })).await .into_iter() - .collect::, ShipError>>()? + .collect::, anyhow::Error>>()? .join("\n") }; Ok(vec![(id, SendShipPacket::SmallLeftDialog(SmallLeftDialog::new(room_info)))]) diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs index 8256a91..36c97d6 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -18,7 +18,7 @@ pub async fn request_exp(id: ClientId, client_location: &ClientLocation, clients: &Clients, rooms: &Rooms) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -29,7 +29,7 @@ where let enemy_exp = rooms.with(room_id, |room| Box::pin(async move { let monster = room.maps.enemy_by_id(enemy_id)?; let monster_stats = room.monster_stats.get(&monster.monster).ok_or_else(|| ShipError::UnknownMonster(monster.monster))?; - Ok::<_, ShipError>(monster_stats.exp) + Ok::<_, anyhow::Error>(monster_stats.exp) })).await??; let exp_gain = if request_exp.last_hitter == 1 { @@ -83,7 +83,7 @@ pub async fn player_drop_item(id: ClientId, clients: &Clients, rooms: &Rooms, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -112,7 +112,7 @@ pub async fn drop_coordinates(id: ClientId, client_location: &ClientLocation, clients: &Clients, rooms: &Rooms) - -> Result, ShipError> + -> Result, anyhow::Error> { let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; let map_area = rooms.with(room_id, |room| Box::pin(async move { @@ -137,7 +137,7 @@ pub async fn no_longer_has_item(id: ClientId, client_location: &ClientLocation, clients: &Clients, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -150,7 +150,7 @@ where })).await?; if let Some(drop_location) = drop_location { if drop_location.item_id.0 != no_longer_has_item.item_id { - return Err(ShipError::DropInvalidItemId(no_longer_has_item.item_id)); + return Err(ShipError::DropInvalidItemId(no_longer_has_item.item_id).into()); } if no_longer_has_item.item_id == 0xFFFFFFFF { @@ -218,7 +218,7 @@ where .collect()) } else { - Err(ShipError::InvalidItem(ClientItemId(no_longer_has_item.item_id))) + Err(ShipError::InvalidItem(ClientItemId(no_longer_has_item.item_id)).into()) } } @@ -227,7 +227,7 @@ pub async fn update_player_position(id: ClientId, clients: &Clients, client_location: &ClientLocation, rooms: &Rooms) - -> Result, ShipError> { + -> Result, anyhow::Error> { if let Ok(room_id) = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() }) { let msg = message.msg.clone(); clients.with_mut(id, |client| { @@ -291,7 +291,7 @@ pub async fn update_player_position(id: ClientId, } _ => {}, } - Ok::<_, ShipError>(()) + Ok::<_, anyhow::Error>(()) })}).await??; } Ok(client_location.get_client_neighbors(id).await?.into_iter() @@ -307,7 +307,7 @@ pub async fn charge_attack(id: ClientId, client_location: &ClientLocation, clients: &Clients, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -333,7 +333,7 @@ pub async fn player_uses_item(id: ClientId, client_location: &ClientLocation, clients: &Clients, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -364,7 +364,7 @@ pub async fn player_used_medical_center(id: ClientId, client_location: &ClientLocation, clients: &Clients, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -390,7 +390,7 @@ pub async fn player_feed_mag(id: ClientId, client_location: &ClientLocation, clients: &Clients, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -415,7 +415,7 @@ pub async fn player_equips_item(id: ClientId, entity_gateway: &mut EG, clients: &Clients, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -440,7 +440,7 @@ pub async fn player_unequips_item(id: ClientId, entity_gateway: &mut EG, clients: &Clients, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -458,7 +458,7 @@ pub async fn player_sorts_items(id: ClientId, entity_gateway: &mut EG, clients: &Clients, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -488,7 +488,7 @@ pub async fn player_sells_item (id: ClientId, entity_gateway: &mut EG, clients: &Clients, item_state: &mut ItemState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { diff --git a/src/ship/packet/handler/quest.rs b/src/ship/packet/handler/quest.rs index a9a5cb2..2bfc265 100644 --- a/src/ship/packet/handler/quest.rs +++ b/src/ship/packet/handler/quest.rs @@ -4,7 +4,7 @@ use libpso::packet::ship::*; use crate::common::serverstate::ClientId; use crate::ship::ship::{SendShipPacket, ShipError, Clients, ShipEvent}; use crate::ship::room::Rooms; -use crate::ship::location::{ClientLocation, ClientLocationError}; +use crate::ship::location::{ClientLocation}; use crate::ship::packet::builder::quest; use libpso::util::array_to_utf8; @@ -13,7 +13,7 @@ enum QuestFileType { Dat } -fn parse_filename(filename_bytes: &[u8; 16]) -> Result<(u16, u16, QuestFileType), ShipError> { +fn parse_filename(filename_bytes: &[u8; 16]) -> Result<(u16, u16, QuestFileType), anyhow::Error> { let filename = array_to_utf8(*filename_bytes).map_err(|_| ShipError::InvalidQuestFilename("NOT UTF8".to_string()))?; let (filename, suffix) = { let mut s = filename.splitn(2, '.'); @@ -24,7 +24,7 @@ fn parse_filename(filename_bytes: &[u8; 16]) -> Result<(u16, u16, QuestFileType) let datatype = match suffix { "bin" => QuestFileType::Bin, "dat" => QuestFileType::Dat, - _ => return Err(ShipError::InvalidQuestFilename(filename.to_owned())) + _ => Err(ShipError::InvalidQuestFilename(filename.to_owned()))? }; let (category, quest) = { @@ -41,8 +41,8 @@ pub async fn send_quest_category_list(id: ClientId, rql: RequestQuestList, client_location: &ClientLocation, rooms: &Rooms) - -> Result, ShipError> { - let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + -> Result, anyhow::Error> { + let room_id = client_location.get_room(id).await?; let rql = rql.clone(); 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]); @@ -55,8 +55,8 @@ pub async fn select_quest_category(id: ClientId, menuselect: MenuSelect, client_location: &ClientLocation, rooms: &Rooms) - -> Result, ShipError> { - let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + -> Result, anyhow::Error> { + let room_id = client_location.get_room(id).await?; rooms.with(room_id, |room| Box::pin(async move { let (_, category_quests) = room.quests[room.quest_group.value()].iter() .nth(menuselect.item as usize) @@ -72,8 +72,8 @@ pub async fn quest_detail(id: ClientId, questdetailrequest: QuestDetailRequest, client_location: &ClientLocation, rooms: &Rooms) - -> Result, ShipError> { - let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + -> Result, anyhow::Error> { + let room_id = client_location.get_room(id).await?; rooms.with(room_id, |room| Box::pin(async move { let (_, category_quests) = room.quests[room.quest_group.value()].iter() .nth(questdetailrequest.category as usize) @@ -96,8 +96,8 @@ pub async fn player_chose_quest(id: ClientId, client_location: &ClientLocation, rooms: &Rooms, event: ShipEvent) - -> Result, ShipError> { - let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + -> Result, anyhow::Error> { + let room_id = client_location.get_room(id).await?; let client_location = client_location.clone(); let questmenuselect = questmenuselect.clone(); @@ -122,7 +122,7 @@ pub async fn player_chose_quest(id: ClientId, 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() })?; + let area_clients = client_location.get_all_clients_by_client(id).await?; for client in &area_clients { clients.with_mut(client.client, |client| Box::pin(async move { client.done_loading_quest = false; @@ -141,9 +141,9 @@ pub async fn quest_file_request(id: ClientId, quest_file_request: QuestFileRequest, client_location: &ClientLocation, rooms: &mut Rooms) - -> Result, ShipError> + -> Result, anyhow::Error> { - 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 quest_file_request = quest_file_request.clone(); rooms.with(room_id, |room| Box::pin(async move { @@ -175,8 +175,8 @@ pub async fn quest_chunk_ack(id: ClientId, quest_chunk_ack: QuestChunkAck, client_location: &ClientLocation, rooms: &Rooms) - -> Result, ShipError> { - let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + -> Result, anyhow::Error> { + let room_id = client_location.get_room(id).await?; let quest_chunk_ack = quest_chunk_ack.clone(); rooms.with(room_id, |room| Box::pin(async move { @@ -211,11 +211,11 @@ pub async fn quest_chunk_ack(id: ClientId, pub async fn done_loading_quest(id: ClientId, clients: &Clients, client_location: &ClientLocation) - -> Result, ShipError> { + -> Result, anyhow::Error> { clients.with_mut(id, |client| Box::pin(async move { client.done_loading_quest = true; })).await?; - 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?; let all_loaded = area_clients.iter() .map(|client| diff --git a/src/ship/packet/handler/room.rs b/src/ship/packet/handler/room.rs index 435d4b8..d19de39 100644 --- a/src/ship/packet/handler/room.rs +++ b/src/ship/packet/handler/room.rs @@ -5,7 +5,7 @@ use libpso::packet::ship::*; use libpso::packet::messages::*; use crate::common::serverstate::ClientId; use crate::common::leveltable::LEVEL_TABLE; -use crate::ship::ship::{SendShipPacket, ShipError, Clients, ShipEvent}; +use crate::ship::ship::{SendShipPacket, Clients, ShipEvent}; use crate::ship::room::Rooms; use crate::ship::location::{ClientLocation, RoomId, RoomLobby, GetAreaError}; use crate::ship::packet::builder; @@ -19,7 +19,7 @@ pub async fn create_room(id: ClientId, item_state: &mut ItemState, rooms: &Rooms, event: ShipEvent) - -> Result, ShipError> { + -> Result, anyhow::Error> { let level = clients.with(id, |client| Box::pin(async move { LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp) })).await?; @@ -47,7 +47,7 @@ pub async fn create_room(id: ClientId, item_state.add_character_to_room(room_id, &client.character, area_client).await; let mut room = room::RoomState::from_create_room(&create_room, client.character.section_id, event)?; room.bursting = true; - Ok::<_, ShipError>(room) + Ok::<_, anyhow::Error>(room) })}).await??; let join_room = builder::room::join_room(id, clients, client_location, room_id, &room, event).await?; @@ -69,7 +69,7 @@ pub async fn create_room(id: ClientId, pub async fn room_name_request(id: ClientId, client_location: &ClientLocation, rooms: &Rooms) - -> Result, ShipError> { + -> Result, anyhow::Error> { let area = client_location.get_area(id).await?; match area { RoomLobby::Room(room) => { @@ -90,7 +90,7 @@ pub async fn join_room(id: ClientId, item_state: &mut ItemState, rooms: &Rooms, event: ShipEvent) - -> Result, ShipError> { + -> Result, anyhow::Error> { let room_id = RoomId(pkt.item as usize); if !rooms.exists(room_id).await { return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("This room no longer exists!".into())))]) @@ -171,7 +171,7 @@ pub async fn join_room(id: ClientId, pub async fn done_bursting(id: ClientId, client_location: &ClientLocation, rooms: &Rooms) - -> Result, ShipError> { + -> Result, anyhow::Error> { let room_id = client_location.get_room(id).await?; let rare_monster_list = rooms.with_mut(room_id, |room| Box::pin(async move { room.bursting = false; @@ -235,7 +235,7 @@ pub async fn request_room_list(id: ClientId, pub async fn cool_62(id: ClientId, cool_62: Like62ButCooler, client_location: &ClientLocation) - -> Result, ShipError> { + -> Result, anyhow::Error> { let target = cool_62.flag as u8; let cool_62 = cool_62.clone(); Ok(client_location diff --git a/src/ship/packet/handler/settings.rs b/src/ship/packet/handler/settings.rs index 58eea70..d2b2500 100644 --- a/src/ship/packet/handler/settings.rs +++ b/src/ship/packet/handler/settings.rs @@ -7,7 +7,7 @@ pub async fn update_config(id: ClientId, update_config: UpdateConfig, clients: &Clients, entity_gateway: &mut EG) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -24,7 +24,7 @@ pub async fn save_options(id: ClientId, save_options: SaveOptions, clients: &Clients, entity_gateway: &mut EG) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -41,7 +41,7 @@ pub async fn keyboard_config(id: ClientId, keyboard_config: KeyboardConfig, clients: &Clients, entity_gateway: &mut EG) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -58,7 +58,7 @@ pub async fn gamepad_config(id: ClientId, gamepad_config: GamepadConfig, clients: &Clients, entity_gateway: &mut EG) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { diff --git a/src/ship/packet/handler/trade.rs b/src/ship/packet/handler/trade.rs index f369f96..c1cb2d0 100644 --- a/src/ship/packet/handler/trade.rs +++ b/src/ship/packet/handler/trade.rs @@ -3,7 +3,7 @@ use libpso::packet::ship::*; use libpso::packet::messages::*; use crate::common::serverstate::ClientId; use crate::ship::ship::{SendShipPacket, ShipError, Clients}; -use crate::ship::location::{ClientLocation, ClientLocationError}; +use crate::ship::location::{ClientLocation}; use crate::ship::items::ClientItemId; use crate::ship::items::state::{ItemState, ItemStateError}; use crate::ship::items::inventory::InventoryItemDetail; @@ -57,9 +57,9 @@ async fn do_trade_action(id: ClientId, this: &mut ClientTradeState, other: &mut ClientTradeState, action: F) - -> Result, ShipError> + -> Result, anyhow::Error> where - F: Fn(&mut ClientTradeState, &mut ClientTradeState) -> Result<(), ShipError>, + F: Fn(&mut ClientTradeState, &mut ClientTradeState) -> Result<(), anyhow::Error>, { Ok(match action(this, other) { Ok(_) => { @@ -92,7 +92,7 @@ pub async fn trade_request(id: ClientId, clients: &Clients, item_state: &mut ItemState, trades: &mut TradeState) - -> Result, ShipError> + -> Result, anyhow::Error> { let trade_request = trade_request.clone(); // TODO: make this function take ownership of packet match trade_request.trade { @@ -293,12 +293,12 @@ async fn inner_items_to_trade(id: ClientId, clients: &Clients, item_state: &mut ItemState, trades: &mut TradeState) - -> Result, ShipError> + -> Result, anyhow::Error> { let pkts = trades .with(&id, |mut this, other| async move { if status_is_not(&this.status, &[TradeStatus::FinalConfirm]) || status_is_not(&other.status, &[TradeStatus::FinalConfirm, TradeStatus::ItemsChecked]) { - return Err(ShipError::from(TradeError::MismatchedStatus)) + return Err(anyhow::Error::from(ShipError::from(TradeError::MismatchedStatus))) } let other_client = other.client(); let (this_inventory, other_inventory) = clients.with(this.client(), |client| { @@ -311,7 +311,7 @@ async fn inner_items_to_trade(id: ClientId, Box::pin(async move { item_state.get_character_inventory(&client.character).await })}).await??; - Ok::<_, ShipError>((this, other_inventory)) + Ok::<_, anyhow::Error>((this, other_inventory)) })}).await??; if items_to_trade.count as usize != (this.items.len() + usize::from(this.meseta != 0)) { @@ -383,7 +383,7 @@ async fn inner_items_to_trade(id: ClientId, } } }) - .collect::, ShipError>>()?; + .collect::, anyhow::Error>>()?; this.status = TradeStatus::ItemsChecked; if this.status == TradeStatus::ItemsChecked && other.status == TradeStatus::ItemsChecked { @@ -418,7 +418,7 @@ pub async fn items_to_trade(id: ClientId, clients: &Clients, item_state: &mut ItemState, trades: &mut TradeState) - -> Result, ShipError> + -> Result, anyhow::Error> { let t = inner_items_to_trade(id, items_to_trade_pkt, client_location, clients, item_state, trades).await; match t { @@ -443,7 +443,7 @@ async fn trade_confirmed_inner(id: ClientId, clients: &Clients, item_state: &mut ItemState, trades: &mut TradeState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { @@ -460,14 +460,14 @@ where .with(&id, |mut this, other| { async move { if status_is_not(&this.status, &[TradeStatus::ItemsChecked]) || status_is_not(&other.status, &[TradeStatus::ItemsChecked, TradeStatus::TradeComplete]) { - return Err(ShipError::TradeError(TradeError::MismatchedStatus)) + return Err(anyhow::Error::from(ShipError::TradeError(TradeError::MismatchedStatus))) } this.status = TradeStatus::TradeComplete; if this.status == TradeStatus::TradeComplete && other.status == TradeStatus::TradeComplete { let this_local_client = client_location.get_local_client(this.client()).await?; let other_local_client = client_location.get_local_client(other.client()).await?; - let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; + let room_id = client_location.get_room(id).await?; Ok(TradeReady::BothPlayers(room_id, (this_local_client, /*this_client, */this.clone()), @@ -584,7 +584,7 @@ pub async fn trade_confirmed(id: ClientId, clients: &Clients, item_state: &mut ItemState, trades: &mut TradeState) - -> Result, ShipError> + -> Result, anyhow::Error> where EG: EntityGateway + Clone + 'static, { diff --git a/src/ship/room.rs b/src/ship/room.rs index ed41b8d..6f8be8a 100644 --- a/src/ship/room.rs +++ b/src/ship/room.rs @@ -29,7 +29,7 @@ impl Default for 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<(), anyhow::Error> { *self.0 .get(room_id.0) .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))? @@ -58,7 +58,7 @@ impl Rooms { } } - pub async fn with<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result + pub async fn with<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result where T: Send, F: for<'b> FnOnce(&'b RoomState) -> BoxFuture<'b, T> + Send + 'a @@ -72,11 +72,11 @@ impl Rooms { Ok(func(room).await) } else { - Err(ShipError::InvalidRoom(room_id.0 as u32)) + Err(ShipError::InvalidRoom(room_id.0 as u32).into()) } } - pub async fn with_mut<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result + pub async fn with_mut<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result where T: Send, F: for<'b> FnOnce(&'b mut RoomState) -> BoxFuture<'b, T> + Send + 'a @@ -91,7 +91,7 @@ impl Rooms { Ok(func(room).await) } else { - Err(ShipError::InvalidRoom(room_id.0 as u32)) + Err(ShipError::InvalidRoom(room_id.0 as u32).into()) } } diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 88cb2a4..e5fc4e5 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -2,6 +2,8 @@ use std::net::Ipv4Addr; use std::collections::HashMap; +use std::backtrace::Backtrace; + use async_std::channel; use async_std::sync::{Arc, Mutex, RwLock}; @@ -162,11 +164,13 @@ pub enum ShipError { SendError(#[from] async_std::channel::SendError), } +/* impl> From for ShipError { fn from(other: I) -> ShipError { ShipError::ClientLocationError(other.into()) } } +*/ #[derive(Debug)] @@ -467,13 +471,13 @@ pub struct Block { pub struct Blocks(pub Vec); impl Blocks { - async fn get_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, anyhow::Error> { let block = clients.with(id, |client| Box::pin(async move { client.block })).await?; self.0 .get_mut(block) - .ok_or_else(|| ShipError::InvalidBlock(block)) + .ok_or_else(|| ShipError::InvalidBlock(block).into()) } } -- 2.36.0 From ab8c5e66887cd1f4c1c990d4256fa4d52bf0b3fe Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 00:55:39 -0700 Subject: [PATCH 03/30] more anyhow --- src/ship/items/actions.rs | 2 +- src/ship/items/tasks.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ship/items/actions.rs b/src/ship/items/actions.rs index f67d149..a9d974a 100644 --- a/src/ship/items/actions.rs +++ b/src/ship/items/actions.rs @@ -977,7 +977,7 @@ where pub(super) fn add_item_to_local_floor( character_id: CharacterEntityId, ) -> impl Fn((ItemStateProxy, TR), FloorItem) - -> BoxFuture> + -> BoxFuture> where EG: EntityGateway, TR: EntityGatewayTransaction + 'static, diff --git a/src/ship/items/tasks.rs b/src/ship/items/tasks.rs index 6d2f355..984e341 100644 --- a/src/ship/items/tasks.rs +++ b/src/ship/items/tasks.rs @@ -466,7 +466,7 @@ pub async fn enemy_drops_item<'a, EG> ( entity_gateway: &mut EG, character_id: CharacterEntityId, item_drop: ItemDrop) - -> Result + -> Result where EG: EntityGateway + 'static, { -- 2.36.0 From 08efcce6f70d5417fb63214388aa7d948a1a8d61 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 00:56:56 -0700 Subject: [PATCH 04/30] mapbuilder --- src/ship/map/enemy.rs | 11 ++- src/ship/map/maps.rs | 149 +++++++++++++++++++------------ src/ship/packet/builder/room.rs | 6 +- src/ship/packet/handler/quest.rs | 5 +- src/ship/packet/handler/room.rs | 6 +- src/ship/room.rs | 46 ++++++---- src/ship/ship.rs | 14 ++- tests/test_rooms.rs | 2 + 8 files changed, 156 insertions(+), 83 deletions(-) diff --git a/src/ship/map/enemy.rs b/src/ship/map/enemy.rs index 79dc3b8..96e63cb 100644 --- a/src/ship/map/enemy.rs +++ b/src/ship/map/enemy.rs @@ -99,9 +99,18 @@ impl RareMonsterAppearTable { } } - pub fn roll_is_rare(&self, monster: &MonsterType) -> bool { + fn roll_is_rare(&self, monster: &MonsterType) -> bool { rand_chacha::ChaChaRng::from_entropy().gen::() < *self.appear_rate.get(monster).unwrap_or(&0.0f32) } + + pub fn apply(&self, mut enemy: MapEnemy, event: ShipEvent) -> MapEnemy { + if enemy.can_be_rare() && self.roll_is_rare(&enemy.monster) { + enemy.into_rare(event) + } + else { + enemy + } + } } diff --git a/src/ship/map/maps.rs b/src/ship/map/maps.rs index 5d04291..46a7189 100644 --- a/src/ship/map/maps.rs +++ b/src/ship/map/maps.rs @@ -8,12 +8,13 @@ use thiserror::Error; use crate::ship::ship::ShipEvent; use crate::ship::monster::MonsterType; -use crate::ship::room::{Episode, RoomMode}; +use crate::ship::room::{Episode, RoomMode, PlayerMode}; // TODO: don't use * use crate::ship::map::*; + pub fn objects_from_stream(cursor: &mut impl Read, episode: &Episode, map_area: &MapArea) -> Vec> { let mut object_data = Vec::new(); @@ -35,7 +36,7 @@ fn parse_enemy(episode: &Episode, map_area: &MapArea, raw_enemy: RawMapEnemy) -> enemy .map_or(vec![None], |monster| { let mut monsters = vec![Some(monster)]; - + match monster.monster { MonsterType::Monest => { for _ in 0..30 { @@ -172,25 +173,10 @@ fn enemy_data_from_map_data(map_variant: &MapVariant, episode: &Episode) -> Vec< } -#[derive(Error, Debug)] -#[error("")] -pub enum MapsError { - InvalidMonsterId(usize), - InvalidObjectId(usize), -} - -#[derive(Debug)] -pub struct Maps { - map_variants: Vec, - enemy_data: Vec>, - object_data: Vec>, -} - -impl Maps { - pub fn new(room_mode: RoomMode, rare_monster_table: &enemy::RareMonsterAppearTable, event: ShipEvent) -> Maps { - let map_variants = match (room_mode.episode(), room_mode.single_player()) { - (Episode::One, 0) => { - vec![MapVariant::new(MapArea::Pioneer2Ep1, MapVariantMode::Online), +fn map_variants(episode: Episode, player_mode: PlayerMode) -> Vec { + match (episode, player_mode) { + (Episode::One, PlayerMode::Multi) => { + vec![MapVariant::new(MapArea::Pioneer2Ep1, MapVariantMode::Online), MapVariant::new(MapArea::Forest1, MapVariantMode::Online), MapVariant::new(MapArea::Forest2, MapVariantMode::Online), MapVariant::new(MapArea::Caves1, MapVariantMode::Online), @@ -205,10 +191,10 @@ impl Maps { MapVariant::new(MapArea::DeRolLe, MapVariantMode::Online), MapVariant::new(MapArea::VolOpt, MapVariantMode::Online), MapVariant::new(MapArea::DarkFalz, MapVariantMode::Online), - ] - }, - (Episode::One, 1) => { - vec![MapVariant::new(MapArea::Pioneer2Ep1, MapVariantMode::Offline), + ] + }, + (Episode::One, PlayerMode::Single) => { + vec![MapVariant::new(MapArea::Pioneer2Ep1, MapVariantMode::Offline), MapVariant::new(MapArea::Forest1, MapVariantMode::Offline), MapVariant::new(MapArea::Forest2, MapVariantMode::Offline), MapVariant::new(MapArea::Caves1, MapVariantMode::Offline), @@ -223,10 +209,10 @@ impl Maps { MapVariant::new(MapArea::DeRolLe, MapVariantMode::Offline), MapVariant::new(MapArea::VolOpt, MapVariantMode::Offline), MapVariant::new(MapArea::DarkFalz, MapVariantMode::Offline), - ] - }, - (Episode::Two, 0) => { - vec![MapVariant::new(MapArea::Pioneer2Ep2, MapVariantMode::Online), + ] + }, + (Episode::Two, PlayerMode::Multi) => { + vec![MapVariant::new(MapArea::Pioneer2Ep2, MapVariantMode::Online), MapVariant::new(MapArea::VrTempleAlpha, MapVariantMode::Online), MapVariant::new(MapArea::VrTempleBeta, MapVariantMode::Online), MapVariant::new(MapArea::VrSpaceshipAlpha, MapVariantMode::Online), @@ -242,10 +228,10 @@ impl Maps { MapVariant::new(MapArea::OlgaFlow, MapVariantMode::Online), MapVariant::new(MapArea::BarbaRay, MapVariantMode::Online), MapVariant::new(MapArea::GolDragon, MapVariantMode::Online), - ] - }, - (Episode::Two, 1) => { - vec![MapVariant::new(MapArea::Pioneer2Ep2, MapVariantMode::Offline), + ] + }, + (Episode::Two, PlayerMode::Single) => { + vec![MapVariant::new(MapArea::Pioneer2Ep2, MapVariantMode::Offline), MapVariant::new(MapArea::VrTempleAlpha, MapVariantMode::Offline), MapVariant::new(MapArea::VrTempleBeta, MapVariantMode::Offline), MapVariant::new(MapArea::VrSpaceshipAlpha, MapVariantMode::Offline), @@ -261,10 +247,10 @@ impl Maps { MapVariant::new(MapArea::OlgaFlow, MapVariantMode::Offline), MapVariant::new(MapArea::BarbaRay, MapVariantMode::Offline), MapVariant::new(MapArea::GolDragon, MapVariantMode::Offline), - ] - }, - (Episode::Four, _) => { - vec![MapVariant::new(MapArea::Pioneer2Ep4, MapVariantMode::Online), + ] + }, + (Episode::Four, PlayerMode::Multi) => { + vec![MapVariant::new(MapArea::Pioneer2Ep4, MapVariantMode::Online), MapVariant::new(MapArea::CraterEast, MapVariantMode::Online), MapVariant::new(MapArea::CraterWest, MapVariantMode::Online), MapVariant::new(MapArea::CraterSouth, MapVariantMode::Online), @@ -274,23 +260,44 @@ impl Maps { MapVariant::new(MapArea::SubDesert2, MapVariantMode::Online), MapVariant::new(MapArea::SubDesert3, MapVariantMode::Online), MapVariant::new(MapArea::SaintMillion, MapVariantMode::Online), - ] - }, - _ => unreachable!() - }; + ] + }, + (Episode::Four, PlayerMode::Single) => { + vec![MapVariant::new(MapArea::Pioneer2Ep4, MapVariantMode::Offline), + MapVariant::new(MapArea::CraterEast, MapVariantMode::Offline), + MapVariant::new(MapArea::CraterWest, MapVariantMode::Offline), + MapVariant::new(MapArea::CraterSouth, MapVariantMode::Offline), + MapVariant::new(MapArea::CraterNorth, MapVariantMode::Offline), + MapVariant::new(MapArea::CraterInterior, MapVariantMode::Offline), + MapVariant::new(MapArea::SubDesert1, MapVariantMode::Offline), + MapVariant::new(MapArea::SubDesert2, MapVariantMode::Offline), + MapVariant::new(MapArea::SubDesert3, MapVariantMode::Offline), + MapVariant::new(MapArea::SaintMillion, MapVariantMode::Offline), + ] + }, + } +} + +#[derive(Error, Debug)] +#[error("")] +pub enum MapsError { + InvalidMonsterId(usize), + InvalidObjectId(usize), +} + +#[derive(Debug)] +pub struct Maps { + map_variants: Vec, + enemy_data: Vec>, + object_data: Vec>, +} +impl Maps { + pub fn new(map_variants: Vec, enemy_data: Vec>, object_data: Vec>) -> Maps { Maps { - enemy_data: map_variants.iter() - .flat_map(|map_variant| { - enemy_data_from_map_data(map_variant, &room_mode.episode()) - }) - .map(|enemy| apply_rare_enemy(enemy, rare_monster_table, event)) - .collect(), - object_data: map_variants.iter() - .flat_map(|map_variant| { - objects_from_map_data(map_variant.obj_file().into(), &room_mode.episode(), &map_variant.map) - }).collect(), map_variants, + enemy_data, + object_data, } } @@ -322,7 +329,7 @@ impl Maps { { self.enemy_data = enemies .into_iter() - .map(|enemy| apply_rare_enemy(enemy, rare_monster_table, event)) + .map(|enemy| enemy.map(|enemy| rare_monster_table.apply(enemy, event))) .collect(); self.object_data = objects; } @@ -351,13 +358,37 @@ impl Maps { } } -fn apply_rare_enemy(enemy: Option, rare_enemy_table: &RareMonsterAppearTable, event: ShipEvent) -> Option { - enemy.map(|enemy| { - if enemy.can_be_rare() && rare_enemy_table.roll_is_rare(&enemy.monster) { - enemy.into_rare(event) +pub trait MapBuilder: Send + Sync { + fn generate_maps(&self, room_mode: RoomMode, event: ShipEvent) -> Maps; +} + +#[derive(Clone)] +pub struct FreeRoamMapBuilder { +} + +impl FreeRoamMapBuilder { + pub fn new() -> FreeRoamMapBuilder { + FreeRoamMapBuilder { } - else { - enemy + } +} + +impl MapBuilder for FreeRoamMapBuilder { + fn generate_maps(&self, room_mode: RoomMode, event: ShipEvent) -> Maps { + let rare_monster_table = RareMonsterAppearTable::new(room_mode.episode()); + let map_variants = map_variants(room_mode.episode(), room_mode.player_mode()); + Maps { + enemy_data: map_variants.iter() + .flat_map(|map_variant| { + enemy_data_from_map_data(map_variant, &room_mode.episode()) + }) + .map(|enemy| enemy.map(|enemy| rare_monster_table.apply(enemy, event))) + .collect(), + object_data: map_variants.iter() + .flat_map(|map_variant| { + objects_from_map_data(map_variant.obj_file().into(), &room_mode.episode(), &map_variant.map) + }).collect(), + map_variants, } - }) + } } diff --git a/src/ship/packet/builder/room.rs b/src/ship/packet/builder/room.rs index acbd5f7..2b5c8e5 100644 --- a/src/ship/packet/builder/room.rs +++ b/src/ship/packet/builder/room.rs @@ -39,14 +39,14 @@ pub async fn join_room(id: ClientId, leader: leader.local_client.id(), one: 1, difficulty: room.mode.difficulty().into(), - battle: room.mode.battle(), + battle: room.mode.battle() as u8, event: event.into(), section: room.section_id.into(), - challenge: room.mode.challenge(), + challenge: room.mode.challenge() as u8, random_seed: room.random_seed, episode: room.mode.episode().into(), one2: 1, - single_player: room.mode.single_player(), + single_player: room.mode.player_mode().value(), unknown: 0, }) } diff --git a/src/ship/packet/handler/quest.rs b/src/ship/packet/handler/quest.rs index 2bfc265..e451f9f 100644 --- a/src/ship/packet/handler/quest.rs +++ b/src/ship/packet/handler/quest.rs @@ -4,6 +4,7 @@ use libpso::packet::ship::*; use crate::common::serverstate::ClientId; use crate::ship::ship::{SendShipPacket, ShipError, Clients, ShipEvent}; use crate::ship::room::Rooms; +use crate::ship::map::enemy::RareMonsterAppearTable; use crate::ship::location::{ClientLocation}; use crate::ship::packet::builder::quest; use libpso::util::array_to_utf8; @@ -115,8 +116,8 @@ pub async fn player_chose_quest(id: ClientId, .ok_or_else(|| ShipError::InvalidQuest(questmenuselect.quest))? .clone(); - let rare_monster_drops = room.rare_monster_table.clone(); - room.maps.set_quest_data(quest.enemies.clone(), quest.objects.clone(), &rare_monster_drops, event); + let rare_monster_table = RareMonsterAppearTable::new(room.mode.episode()); + room.maps.set_quest_data(quest.enemies.clone(), quest.objects.clone(), &rare_monster_table, event); room.map_areas = quest.map_areas.clone(); let bin = quest::quest_header(&questmenuselect, &quest.bin_blob, "bin"); diff --git a/src/ship/packet/handler/room.rs b/src/ship/packet/handler/room.rs index d19de39..3a5fc6c 100644 --- a/src/ship/packet/handler/room.rs +++ b/src/ship/packet/handler/room.rs @@ -1,12 +1,15 @@ use std::convert::{TryFrom, Into}; use futures::stream::StreamExt; +use async_std::sync::Arc; + use libpso::packet::ship::*; use libpso::packet::messages::*; use crate::common::serverstate::ClientId; use crate::common::leveltable::LEVEL_TABLE; use crate::ship::ship::{SendShipPacket, Clients, ShipEvent}; use crate::ship::room::Rooms; +use crate::ship::map::MapBuilder; use crate::ship::location::{ClientLocation, RoomId, RoomLobby, GetAreaError}; use crate::ship::packet::builder; use crate::ship::room; @@ -18,6 +21,7 @@ pub async fn create_room(id: ClientId, clients: &Clients, item_state: &mut ItemState, rooms: &Rooms, + map_builder: Arc>, event: ShipEvent) -> Result, anyhow::Error> { let level = clients.with(id, |client| Box::pin(async move { @@ -45,7 +49,7 @@ pub async fn create_room(id: ClientId, let mut item_state = item_state.clone(); Box::pin(async move { item_state.add_character_to_room(room_id, &client.character, area_client).await; - let mut room = room::RoomState::from_create_room(&create_room, client.character.section_id, event)?; + let mut room = room::RoomState::from_create_room(&create_room, map_builder, client.character.section_id, event)?; room.bursting = true; Ok::<_, anyhow::Error>(room) })}).await??; diff --git a/src/ship/room.rs b/src/ship/room.rs index 6f8be8a..523169a 100644 --- a/src/ship/room.rs +++ b/src/ship/room.rs @@ -8,7 +8,7 @@ use futures::stream::{FuturesOrdered, Stream}; use thiserror::Error; use rand::Rng; -use crate::ship::map::Maps; +use crate::ship::map::{Maps, MapBuilder}; use crate::ship::drops::DropTable; use crate::entity::character::SectionID; use crate::ship::monster::{load_monster_stats_table, MonsterType, MonsterStats}; @@ -135,6 +135,21 @@ pub enum Episode { Four, } +#[derive(Debug, Copy, Clone)] +pub enum PlayerMode{ + Single, + Multi, +} + +impl PlayerMode { + pub fn value(&self) -> u8 { + match self { + PlayerMode::Single => 1, + PlayerMode::Multi => 0, + } + } +} + impl TryFrom for Episode { type Error = RoomCreationError; @@ -245,24 +260,24 @@ impl RoomMode { } } - pub fn battle(&self) -> u8 { + pub fn battle(&self) -> bool { match self { - RoomMode::Battle {..} => 1, - _ => 0, + RoomMode::Battle {..} => true, + _ => false, } } - pub fn challenge(&self) -> u8 { + pub fn challenge(&self) -> bool { match self { - RoomMode::Challenge {..} => 1, - _ => 0, + RoomMode::Challenge {..} => true, + _ => false, } } - pub fn single_player(&self) -> u8 { + pub fn player_mode(&self) -> PlayerMode { match self { - RoomMode::Single {..} => 1, - _ => 0, + RoomMode::Single {..} => PlayerMode::Single, + _ => PlayerMode::Multi, } } } @@ -301,7 +316,6 @@ pub struct RoomState { pub bursting: bool, pub monster_stats: Box>, pub map_areas: MapAreaLookup, - pub rare_monster_table: Box, pub quest_group: QuestCategoryType, pub quests: Vec, // items on ground @@ -343,7 +357,11 @@ impl RoomState { self.quest_group = QuestCategoryType::from(group); } - pub fn from_create_room(create_room: &libpso::packet::ship::CreateRoom, section_id: SectionID, event: ShipEvent) -> Result { + pub fn from_create_room(create_room: &libpso::packet::ship::CreateRoom, + map_builder: Arc>, + section_id: SectionID, + event: ShipEvent) + -> Result { if [create_room.battle, create_room.challenge, create_room.single_player].iter().sum::() > 1 { return Err(RoomCreationError::InvalidMode) } @@ -372,7 +390,6 @@ impl RoomState { } }; - let rare_monster_table = RareMonsterAppearTable::new(room_mode.episode()); // push the usual set of quests for the selected mode let mut qpath = PathBuf::from("data/quests/bb"); @@ -407,10 +424,9 @@ impl RoomState { monster_stats: Box::new(load_monster_stats_table(&room_mode).map_err(|_| RoomCreationError::CouldNotLoadMonsterStats(room_mode))?), mode: room_mode, random_seed: rand::thread_rng().gen(), - rare_monster_table: Box::new(rare_monster_table.clone()), name: String::from_utf16_lossy(&create_room.name).trim_matches(char::from(0)).into(), password: create_room.password, - maps: Maps::new(room_mode, &rare_monster_table, event), + maps: map_builder.generate_maps(room_mode, event), section_id, drop_table: Box::new(DropTable::new(room_mode.episode(), room_mode.difficulty(), section_id)), bursting: false, diff --git a/src/ship/ship.rs b/src/ship/ship.rs index e5fc4e5..02c2ecd 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -32,7 +32,7 @@ use crate::ship::location::{ClientLocation, RoomLobby, ClientLocationError, Room use crate::ship::items; use crate::ship::room; -use crate::ship::map::{MapsError, MapAreaError}; +use crate::ship::map::{Maps, MapBuilder, FreeRoamMapBuilder, MapsError, MapAreaError}; use crate::ship::packet::handler; use crate::ship::shops::{WeaponShop, ToolShop, ArmorShop}; use crate::ship::trade::TradeState; @@ -379,6 +379,7 @@ pub struct ShipServerStateBuilder { port: Option, auth_token: Option, event: Option, + map_builder: Option>, num_blocks: usize, } @@ -391,6 +392,7 @@ impl Default for ShipServerStateBuilder port: None, auth_token: None, event: None, + map_builder: None, num_blocks: 2, } } @@ -433,6 +435,12 @@ impl ShipServerStateBuilder { self } + #[must_use] + pub fn map_builder(mut self, map_builder: Box) -> ShipServerStateBuilder { + self.map_builder = Some(map_builder); + self + } + #[must_use] pub fn blocks(mut self, num_blocks: usize) -> ShipServerStateBuilder { self.num_blocks = num_blocks; @@ -451,6 +459,7 @@ impl ShipServerStateBuilder { shops: ItemShops::default(), blocks: Blocks(blocks), event: self.event.unwrap_or(ShipEvent::None), + map_builder: Arc::new(self.map_builder.unwrap_or(Box::new(FreeRoamMapBuilder::new()))), auth_token: self.auth_token.unwrap_or_else(|| AuthToken("".into())), ship_list: Arc::new(RwLock::new(Vec::new())), @@ -499,6 +508,7 @@ pub struct ShipServerState { ship_list: Arc>>, shipgate_sender: Option>, trades: TradeState, + map_builder: Arc>, } impl ShipServerState { @@ -725,7 +735,7 @@ impl ServerState for ShipServerState { }, RecvShipPacket::CreateRoom(create_room) => { 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, self.event).await? + handler::room::create_room(id, create_room, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, self.map_builder.clone(), self.event).await? }, RecvShipPacket::RoomNameRequest(_req) => { let block = self.blocks.get_from_client(id, &self.clients).await?; diff --git a/tests/test_rooms.rs b/tests/test_rooms.rs index 55635c6..45a5210 100644 --- a/tests/test_rooms.rs +++ b/tests/test_rooms.rs @@ -97,6 +97,7 @@ async fn test_item_ids_reset_when_rejoining_rooms() { } } +/* #[async_std::test] async fn test_load_rare_monster_default_appear_rates() { let mut entity_gateway = InMemoryGateway::default(); @@ -116,6 +117,7 @@ async fn test_load_rare_monster_default_appear_rates() { } })).await.unwrap(); } +*/ #[async_std::test] async fn test_set_valid_quest_group() { -- 2.36.0 From 62387366e47619a4a9a3e79a0e23acdfdb68be53 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 01:00:29 -0700 Subject: [PATCH 05/30] fix anyhow-inflicted tests --- tests/test_shops.rs | 3 ++- tests/test_trade.rs | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/test_shops.rs b/tests/test_shops.rs index 32244d0..cf230c9 100644 --- a/tests/test_shops.rs +++ b/tests/test_shops.rs @@ -1143,7 +1143,8 @@ async fn test_player_cant_sell_if_meseta_would_go_over_max() { amount: 1, })))).await.err().unwrap(); //assert_eq!(ack, ShipError::ItemStateError(ItemStateError::FullOfMeseta)); - assert!(matches!(ack.downcast::().unwrap(), ShipError::ItemStateError(ItemStateError::FullOfMeseta))); + assert!(matches!(ack.downcast::().unwrap(), ItemStateError::FullOfMeseta)); + //assert!(matches!(ack.downcast::().unwrap(), ShipError::ItemStateError(ItemStateError::FullOfMeseta))); let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); assert_eq!(c1_meseta.0, 999995); diff --git a/tests/test_trade.rs b/tests/test_trade.rs index 61bff99..4155a46 100644 --- a/tests/test_trade.rs +++ b/tests/test_trade.rs @@ -3155,7 +3155,7 @@ async fn test_client_tries_to_start_two_trades() { trade: TradeRequestCommand::Initialize(TradeRequestInitializeCommand::Initialize, 0) })))).await.err().unwrap(); - assert!(matches!(ack.downcast::().unwrap(), ShipError::TradeError(TradeError::ClientAlreadyInTrade))); + assert!(matches!(ack.downcast::().unwrap(), TradeError::ClientAlreadyInTrade)); } #[async_std::test] @@ -3187,14 +3187,14 @@ async fn test_client_tries_trading_with_client_already_trading() { target: 0, trade: TradeRequestCommand::Initialize(TradeRequestInitializeCommand::Initialize, 0) })))).await.err().unwrap(); - assert!(matches!(ack.downcast::().unwrap(), ShipError::TradeError(TradeError::OtherAlreadyInTrade))); + assert!(matches!(ack.downcast::().unwrap(), TradeError::OtherAlreadyInTrade)); let ack = ship.handle(ClientId(3), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest { client: 2, target: 0, trade: TradeRequestCommand::Initialize(TradeRequestInitializeCommand::Initialize, 1) })))).await.err().unwrap(); - assert!(matches!(ack.downcast::().unwrap(), ShipError::TradeError(TradeError::OtherAlreadyInTrade))); + assert!(matches!(ack.downcast::().unwrap(), TradeError::OtherAlreadyInTrade)); } #[async_std::test] -- 2.36.0 From e5f13b6cb73d323d6ac6f35887d5380aa4f249c5 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 11:51:55 -0700 Subject: [PATCH 06/30] why did I make this generic over rng anyway its not like I was ever gonna use that --- src/ship/drops/mod.rs | 12 ++++++------ src/ship/room.rs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ship/drops/mod.rs b/src/ship/drops/mod.rs index 5e9747f..e4f695d 100644 --- a/src/ship/drops/mod.rs +++ b/src/ship/drops/mod.rs @@ -112,7 +112,7 @@ pub struct ItemDrop { } -pub struct DropTable { +pub struct DropTable { monster_stats: HashMap, rare_table: RareDropTable, weapon_table: GenericWeaponTable, @@ -121,11 +121,11 @@ pub struct DropTable { unit_table: GenericUnitTable, tool_table: ToolTable, box_table: BoxDropTable, - rng: R, + rng: rand_chacha::ChaCha20Rng, } -impl DropTable { - pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable { +impl DropTable { + pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable { let monster_stats: HashMap = load_data_file(episode, difficulty, section_id, "monster_dar.toml"); DropTable { @@ -137,7 +137,7 @@ impl DropTable { unit_table: GenericUnitTable::new(episode, difficulty, section_id), tool_table: ToolTable::new(episode, difficulty, section_id), box_table: BoxDropTable::new(episode, difficulty, section_id), - rng: R::from_entropy(), + rng: rand_chacha::ChaCha20Rng::from_entropy(), } } @@ -203,6 +203,6 @@ mod test { let section_id = vec![SectionID::Viridia, SectionID::Greenill, SectionID::Skyly, SectionID::Bluefull, SectionID::Purplenum, SectionID::Pinkal, SectionID::Redria, SectionID::Oran, SectionID::Yellowboze, SectionID::Whitill] .into_iter().choose(&mut rng).unwrap(); - DropTable::::new(episode, difficulty, section_id); + DropTable::new(episode, difficulty, section_id); } } diff --git a/src/ship/room.rs b/src/ship/room.rs index 523169a..31e0b87 100644 --- a/src/ship/room.rs +++ b/src/ship/room.rs @@ -310,7 +310,7 @@ pub struct RoomState { pub name: String, pub password: [u16; 16], pub maps: Maps, - pub drop_table: Box>, + pub drop_table: Box, pub section_id: SectionID, pub random_seed: u32, pub bursting: bool, -- 2.36.0 From b831f9b83b409ce7008c46c8f2ad4bb71b995973 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 12:35:46 -0700 Subject: [PATCH 07/30] drop table builder --- src/ship/packet/handler/room.rs | 22 ++++++++++++---------- src/ship/room.rs | 5 ++--- src/ship/ship.rs | 15 +++++++++++++-- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/ship/packet/handler/room.rs b/src/ship/packet/handler/room.rs index 3a5fc6c..f5f2a85 100644 --- a/src/ship/packet/handler/room.rs +++ b/src/ship/packet/handler/room.rs @@ -7,12 +7,13 @@ use libpso::packet::ship::*; use libpso::packet::messages::*; use crate::common::serverstate::ClientId; use crate::common::leveltable::LEVEL_TABLE; +use crate::entity::character::SectionID; +use crate::ship::drops::DropTable; use crate::ship::ship::{SendShipPacket, Clients, ShipEvent}; -use crate::ship::room::Rooms; +use crate::ship::room::{Rooms, Episode, Difficulty, RoomState}; use crate::ship::map::MapBuilder; use crate::ship::location::{ClientLocation, RoomId, RoomLobby, GetAreaError}; use crate::ship::packet::builder; -use crate::ship::room; use crate::ship::items::state::ItemState; pub async fn create_room(id: ClientId, @@ -22,19 +23,20 @@ pub async fn create_room(id: ClientId, item_state: &mut ItemState, rooms: &Rooms, map_builder: Arc>, + drop_table_builder: Arc DropTable + Send + Sync>>, event: ShipEvent) -> Result, anyhow::Error> { let level = clients.with(id, |client| Box::pin(async move { LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp) })).await?; - match room::Difficulty::try_from(create_room.difficulty)? { - room::Difficulty::Ultimate if level < 80 => { + match Difficulty::try_from(create_room.difficulty)? { + Difficulty::Ultimate if level < 80 => { return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 80 \nto create Ultimate rooms.".into())))]) }, - room::Difficulty::VeryHard if level < 40 => { + Difficulty::VeryHard if level < 40 => { return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 40 \nto create Very Hard rooms.".into())))]) }, - room::Difficulty::Hard if level < 20 => { + Difficulty::Hard if level < 20 => { return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 20 \nto create Hard rooms.".into())))]) }, _ => {}, @@ -49,7 +51,7 @@ pub async fn create_room(id: ClientId, let mut item_state = item_state.clone(); Box::pin(async move { item_state.add_character_to_room(room_id, &client.character, area_client).await; - let mut room = room::RoomState::from_create_room(&create_room, map_builder, client.character.section_id, event)?; + let mut room = RoomState::from_create_room(&create_room, map_builder, drop_table_builder, client.character.section_id, event)?; room.bursting = true; Ok::<_, anyhow::Error>(room) })}).await??; @@ -107,13 +109,13 @@ pub async fn join_room(id: ClientId, })).await?; match difficulty { - room::Difficulty::Ultimate if level < 80 => { + Difficulty::Ultimate if level < 80 => { return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 80 \nto join Ultimate rooms.".into())))]) }, - room::Difficulty::VeryHard if level < 40 => { + Difficulty::VeryHard if level < 40 => { return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 40 \nto join Very Hard rooms.".into())))]) }, - room::Difficulty::Hard if level < 20 => { + Difficulty::Hard if level < 20 => { return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 20 \nto join Hard rooms.".into())))]) }, _ => {}, diff --git a/src/ship/room.rs b/src/ship/room.rs index 31e0b87..6b9462a 100644 --- a/src/ship/room.rs +++ b/src/ship/room.rs @@ -359,6 +359,7 @@ impl RoomState { pub fn from_create_room(create_room: &libpso::packet::ship::CreateRoom, map_builder: Arc>, + drop_table_builder: Arc DropTable + Send + Sync>>, section_id: SectionID, event: ShipEvent) -> Result { @@ -418,8 +419,6 @@ impl RoomState { room_quests.push(quest_list); } - - Ok(RoomState { monster_stats: Box::new(load_monster_stats_table(&room_mode).map_err(|_| RoomCreationError::CouldNotLoadMonsterStats(room_mode))?), mode: room_mode, @@ -428,7 +427,7 @@ impl RoomState { password: create_room.password, maps: map_builder.generate_maps(room_mode, event), section_id, - drop_table: Box::new(DropTable::new(room_mode.episode(), room_mode.difficulty(), section_id)), + drop_table: Box::new(drop_table_builder(room_mode.episode(), room_mode.difficulty(), section_id)), bursting: false, map_areas: MapAreaLookup::new(&room_mode.episode()), quest_group: QuestCategoryType::Standard, diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 02c2ecd..8576b69 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -30,9 +30,10 @@ use crate::entity::character::SectionID; use crate::ship::location::{ClientLocation, RoomLobby, ClientLocationError, RoomId}; +use crate::ship::drops::DropTable; use crate::ship::items; use crate::ship::room; -use crate::ship::map::{Maps, MapBuilder, FreeRoamMapBuilder, MapsError, MapAreaError}; +use crate::ship::map::{MapBuilder, FreeRoamMapBuilder, MapsError, MapAreaError}; use crate::ship::packet::handler; use crate::ship::shops::{WeaponShop, ToolShop, ArmorShop}; use crate::ship::trade::TradeState; @@ -380,6 +381,7 @@ pub struct ShipServerStateBuilder { auth_token: Option, event: Option, map_builder: Option>, + drop_table_builder: Option DropTable + Send + Sync>>, num_blocks: usize, } @@ -393,6 +395,7 @@ impl Default for ShipServerStateBuilder auth_token: None, event: None, map_builder: None, + drop_table_builder: None, num_blocks: 2, } } @@ -441,6 +444,12 @@ impl ShipServerStateBuilder { self } + #[must_use] + pub fn drop_table_builder(mut self, drop_table_builder: Box DropTable + Send + Sync>) -> ShipServerStateBuilder { + self.drop_table_builder = Some(drop_table_builder); + self + } + #[must_use] pub fn blocks(mut self, num_blocks: usize) -> ShipServerStateBuilder { self.num_blocks = num_blocks; @@ -460,6 +469,7 @@ impl ShipServerStateBuilder { blocks: Blocks(blocks), event: self.event.unwrap_or(ShipEvent::None), map_builder: Arc::new(self.map_builder.unwrap_or(Box::new(FreeRoamMapBuilder::new()))), + drop_table_builder: Arc::new(self.drop_table_builder.unwrap_or(Box::new(DropTable::new))), auth_token: self.auth_token.unwrap_or_else(|| AuthToken("".into())), ship_list: Arc::new(RwLock::new(Vec::new())), @@ -509,6 +519,7 @@ pub struct ShipServerState { shipgate_sender: Option>, trades: TradeState, map_builder: Arc>, + drop_table_builder: Arc DropTable + Send + Sync>>, } impl ShipServerState { @@ -735,7 +746,7 @@ impl ServerState for ShipServerState { }, RecvShipPacket::CreateRoom(create_room) => { 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, self.map_builder.clone(), self.event).await? + handler::room::create_room(id, create_room, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, self.map_builder.clone(), self.drop_table_builder.clone(), self.event).await? }, RecvShipPacket::RoomNameRequest(_req) => { let block = self.blocks.get_from_client(id, &self.clients).await?; -- 2.36.0 From 33b80d7235059abe3854abecdf9253b14b01ed1c Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 12:48:42 -0700 Subject: [PATCH 08/30] mapbuilder trait -> just a function --- src/ship/map/maps.rs | 47 +++++++++++---------------------- src/ship/packet/handler/room.rs | 6 ++--- src/ship/room.rs | 6 ++--- src/ship/ship.rs | 10 +++---- 4 files changed, 26 insertions(+), 43 deletions(-) diff --git a/src/ship/map/maps.rs b/src/ship/map/maps.rs index 46a7189..94d2193 100644 --- a/src/ship/map/maps.rs +++ b/src/ship/map/maps.rs @@ -358,37 +358,20 @@ impl Maps { } } -pub trait MapBuilder: Send + Sync { - fn generate_maps(&self, room_mode: RoomMode, event: ShipEvent) -> Maps; -} - -#[derive(Clone)] -pub struct FreeRoamMapBuilder { -} - -impl FreeRoamMapBuilder { - pub fn new() -> FreeRoamMapBuilder { - FreeRoamMapBuilder { - } - } -} - -impl MapBuilder for FreeRoamMapBuilder { - fn generate_maps(&self, room_mode: RoomMode, event: ShipEvent) -> Maps { - let rare_monster_table = RareMonsterAppearTable::new(room_mode.episode()); - let map_variants = map_variants(room_mode.episode(), room_mode.player_mode()); - Maps { - enemy_data: map_variants.iter() - .flat_map(|map_variant| { - enemy_data_from_map_data(map_variant, &room_mode.episode()) - }) - .map(|enemy| enemy.map(|enemy| rare_monster_table.apply(enemy, event))) - .collect(), - object_data: map_variants.iter() - .flat_map(|map_variant| { - objects_from_map_data(map_variant.obj_file().into(), &room_mode.episode(), &map_variant.map) - }).collect(), - map_variants, - } +pub fn generate_free_roam_maps(room_mode: RoomMode, event: ShipEvent) -> Maps { + let rare_monster_table = RareMonsterAppearTable::new(room_mode.episode()); + let map_variants = map_variants(room_mode.episode(), room_mode.player_mode()); + Maps { + enemy_data: map_variants.iter() + .flat_map(|map_variant| { + enemy_data_from_map_data(map_variant, &room_mode.episode()) + }) + .map(|enemy| enemy.map(|enemy| rare_monster_table.apply(enemy, event))) + .collect(), + object_data: map_variants.iter() + .flat_map(|map_variant| { + objects_from_map_data(map_variant.obj_file().into(), &room_mode.episode(), &map_variant.map) + }).collect(), + map_variants, } } diff --git a/src/ship/packet/handler/room.rs b/src/ship/packet/handler/room.rs index f5f2a85..0a108ca 100644 --- a/src/ship/packet/handler/room.rs +++ b/src/ship/packet/handler/room.rs @@ -10,8 +10,8 @@ use crate::common::leveltable::LEVEL_TABLE; use crate::entity::character::SectionID; use crate::ship::drops::DropTable; use crate::ship::ship::{SendShipPacket, Clients, ShipEvent}; -use crate::ship::room::{Rooms, Episode, Difficulty, RoomState}; -use crate::ship::map::MapBuilder; +use crate::ship::room::{Rooms, Episode, Difficulty, RoomState, RoomMode}; +use crate::ship::map::Maps; use crate::ship::location::{ClientLocation, RoomId, RoomLobby, GetAreaError}; use crate::ship::packet::builder; use crate::ship::items::state::ItemState; @@ -22,7 +22,7 @@ pub async fn create_room(id: ClientId, clients: &Clients, item_state: &mut ItemState, rooms: &Rooms, - map_builder: Arc>, + map_builder: Arc Maps + Send + Sync>>, drop_table_builder: Arc DropTable + Send + Sync>>, event: ShipEvent) -> Result, anyhow::Error> { diff --git a/src/ship/room.rs b/src/ship/room.rs index 6b9462a..a48bfc3 100644 --- a/src/ship/room.rs +++ b/src/ship/room.rs @@ -8,7 +8,7 @@ use futures::stream::{FuturesOrdered, Stream}; use thiserror::Error; use rand::Rng; -use crate::ship::map::{Maps, MapBuilder}; +use crate::ship::map::Maps; use crate::ship::drops::DropTable; use crate::entity::character::SectionID; use crate::ship::monster::{load_monster_stats_table, MonsterType, MonsterStats}; @@ -358,7 +358,7 @@ impl RoomState { } pub fn from_create_room(create_room: &libpso::packet::ship::CreateRoom, - map_builder: Arc>, + map_builder: Arc Maps + Send + Sync>>, drop_table_builder: Arc DropTable + Send + Sync>>, section_id: SectionID, event: ShipEvent) @@ -425,7 +425,7 @@ impl RoomState { random_seed: rand::thread_rng().gen(), name: String::from_utf16_lossy(&create_room.name).trim_matches(char::from(0)).into(), password: create_room.password, - maps: map_builder.generate_maps(room_mode, event), + maps: map_builder(room_mode, event), section_id, drop_table: Box::new(drop_table_builder(room_mode.episode(), room_mode.difficulty(), section_id)), bursting: false, diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 8576b69..fc5581c 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -33,7 +33,7 @@ use crate::ship::location::{ClientLocation, RoomLobby, ClientLocationError, Room use crate::ship::drops::DropTable; use crate::ship::items; use crate::ship::room; -use crate::ship::map::{MapBuilder, FreeRoamMapBuilder, MapsError, MapAreaError}; +use crate::ship::map::{Maps, MapsError, MapAreaError, generate_free_roam_maps}; use crate::ship::packet::handler; use crate::ship::shops::{WeaponShop, ToolShop, ArmorShop}; use crate::ship::trade::TradeState; @@ -380,7 +380,7 @@ pub struct ShipServerStateBuilder { port: Option, auth_token: Option, event: Option, - map_builder: Option>, + map_builder: Option Maps + Send + Sync>>, drop_table_builder: Option DropTable + Send + Sync>>, num_blocks: usize, } @@ -439,7 +439,7 @@ impl ShipServerStateBuilder { } #[must_use] - pub fn map_builder(mut self, map_builder: Box) -> ShipServerStateBuilder { + pub fn map_builder(mut self, map_builder: Box Maps + Send + Sync>) -> ShipServerStateBuilder { self.map_builder = Some(map_builder); self } @@ -468,7 +468,7 @@ impl ShipServerStateBuilder { shops: ItemShops::default(), blocks: Blocks(blocks), event: self.event.unwrap_or(ShipEvent::None), - map_builder: Arc::new(self.map_builder.unwrap_or(Box::new(FreeRoamMapBuilder::new()))), + map_builder: Arc::new(self.map_builder.unwrap_or(Box::new(generate_free_roam_maps))), drop_table_builder: Arc::new(self.drop_table_builder.unwrap_or(Box::new(DropTable::new))), auth_token: self.auth_token.unwrap_or_else(|| AuthToken("".into())), @@ -518,7 +518,7 @@ pub struct ShipServerState { ship_list: Arc>>, shipgate_sender: Option>, trades: TradeState, - map_builder: Arc>, + map_builder: Arc Maps + Send + Sync>>, drop_table_builder: Arc DropTable + Send + Sync>>, } -- 2.36.0 From bbaf39fa0be59c685e36d13eeff5611589642a51 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 13:07:41 -0700 Subject: [PATCH 09/30] rename default_map_variants --- src/ship/map/maps.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ship/map/maps.rs b/src/ship/map/maps.rs index 94d2193..05c7e29 100644 --- a/src/ship/map/maps.rs +++ b/src/ship/map/maps.rs @@ -173,7 +173,7 @@ fn enemy_data_from_map_data(map_variant: &MapVariant, episode: &Episode) -> Vec< } -fn map_variants(episode: Episode, player_mode: PlayerMode) -> Vec { +pub fn default_map_variants(episode: Episode, player_mode: PlayerMode) -> Vec { match (episode, player_mode) { (Episode::One, PlayerMode::Multi) => { vec![MapVariant::new(MapArea::Pioneer2Ep1, MapVariantMode::Online), @@ -360,7 +360,7 @@ impl Maps { pub fn generate_free_roam_maps(room_mode: RoomMode, event: ShipEvent) -> Maps { let rare_monster_table = RareMonsterAppearTable::new(room_mode.episode()); - let map_variants = map_variants(room_mode.episode(), room_mode.player_mode()); + let map_variants = default_map_variants(room_mode.episode(), room_mode.player_mode()); Maps { enemy_data: map_variants.iter() .flat_map(|map_variant| { -- 2.36.0 From 220d3e71854fd77556687ae65dfae384069f1832 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 13:08:07 -0700 Subject: [PATCH 10/30] update exp tests with new map builder tech --- src/ship/map/mod.rs | 6 +- tests/test_exp_gain.rs | 129 +++++++++++++++++------------------------ 2 files changed, 57 insertions(+), 78 deletions(-) diff --git a/src/ship/map/mod.rs b/src/ship/map/mod.rs index 6c54343..693fd46 100644 --- a/src/ship/map/mod.rs +++ b/src/ship/map/mod.rs @@ -1,8 +1,8 @@ pub mod area; pub mod enemy; -mod object; -mod variant; -mod maps; +pub mod object; +pub mod variant; +pub mod maps; // TODO: don't just forward everything to the module scope pub use area::*; diff --git a/tests/test_exp_gain.rs b/tests/test_exp_gain.rs index 4584571..465f949 100644 --- a/tests/test_exp_gain.rs +++ b/tests/test_exp_gain.rs @@ -4,6 +4,10 @@ use elseware::common::leveltable::CharacterLevelTable; use elseware::ship::ship::{ShipServerState, SendShipPacket, RecvShipPacket}; use elseware::ship::monster::MonsterType; use elseware::ship::location::RoomId; +use elseware::ship::map::variant::{MapVariant, MapVariantMode}; +use elseware::ship::map::maps::Maps; +use elseware::ship::map::area::MapArea; +use elseware::ship::map::enemy::MapEnemy; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -19,36 +23,30 @@ async fn test_character_gains_exp() { let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + .gateway(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .build()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - let (enemy_id, exp) = { - //let room = ship.blocks.0[0].rooms.get(RoomId(0)).as_ref().unwrap(); - ship.blocks.0[0].rooms.with(RoomId(0), |room| Box::pin(async move { - let (enemy_id, map_enemy) = (0..).filter_map(|i| { - room.maps.enemy_by_id(i).map(|enemy| { - (i, enemy) - }).ok() - }).next().unwrap(); - let map_enemy_stats = room.monster_stats.get(&map_enemy.monster).unwrap(); - (enemy_id, map_enemy_stats.exp) - })).await.unwrap() - }; - ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::RequestExp(RequestExp { - client: enemy_id as u8, + client: 0, target: 16, - enemy_id: enemy_id as u16, + enemy_id: 0, client_id: 0, unused: 0, last_hitter: 1, })))).await.unwrap(); ship.clients.with(ClientId(1), |client| Box::pin(async move { - assert!(exp == client.character.exp); + assert!(13 == client.character.exp); })).await.unwrap(); } @@ -61,24 +59,23 @@ async fn test_character_levels_up() { entity_gateway.save_character(&char1).await.unwrap(); let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + .gateway(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .build()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - let enemy_id = ship.blocks.0[0].rooms.with(RoomId(0), |room| Box::pin(async move { - (0..).filter_map(|i| { - room.maps.enemy_by_id(i).map(|_| { - i - }).ok() - }).next().unwrap() - })).await.unwrap(); - let levelup_pkt = ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::RequestExp(RequestExp { - client: enemy_id as u8, + client: 0 as u8, target: 16, - enemy_id: enemy_id as u16, + enemy_id: 0 as u16, client_id: 0, unused: 0, last_hitter: 1, @@ -99,33 +96,23 @@ async fn test_character_levels_up_multiple_times() { let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + .gateway(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::DarkFalz, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::DarkFalz2, MapArea::DarkFalz))], + Vec::new(), + ) + })) + .build()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; create_room(&mut ship, ClientId(1), "room", "").await; - let (enemy_id, exp) = { - ship.blocks.0[0].rooms.with(RoomId(0), |room| Box::pin(async move { - let (enemy_id, map_enemy) = (0..).filter_map(|i| { - room.maps.enemy_by_id(i).ok().and_then(|enemy| { - if enemy.monster == MonsterType::DarkFalz2 { - Some((i, enemy)) - } - else { - None - } - }) - }).next().unwrap(); - let map_enemy_stats = room.monster_stats.get(&map_enemy.monster).unwrap(); - (enemy_id, map_enemy_stats.exp) - })).await.unwrap() - }; - let levelup_pkt = ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::RequestExp(RequestExp { - client: enemy_id as u8, + client: 0 as u8, target: 16, - enemy_id: enemy_id as u16, + enemy_id: 0 as u16, client_id: 0, unused: 0, last_hitter: 1, @@ -134,7 +121,7 @@ async fn test_character_levels_up_multiple_times() { assert!(matches!(levelup_pkt[1].1, SendShipPacket::Message(Message {msg: GameMessage::PlayerLevelUp(PlayerLevelUp {lvl: 8, ..})}))); ship.clients.with(ClientId(1), |client| Box::pin(async move { - assert!(exp == client.character.exp); + assert!(3000 == client.character.exp); })).await.unwrap(); } @@ -146,8 +133,15 @@ async fn test_one_character_gets_full_exp_and_other_attacker_gets_partial() { let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; let mut ship = Box::new(ShipServerState::builder() - .gateway(entity_gateway.clone()) - .build()); + .gateway(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .build()); log_in_char(&mut ship, ClientId(1), "a1", "a").await; log_in_char(&mut ship, ClientId(2), "a2", "a").await; @@ -157,43 +151,28 @@ async fn test_one_character_gets_full_exp_and_other_attacker_gets_partial() { create_room(&mut ship, ClientId(1), "room", "").await; join_room(&mut ship, ClientId(2), 0).await; - let (enemy_id, exp) = ship.blocks.0[0].rooms.with(RoomId(0), |room| Box::pin(async move { - let (enemy_id, map_enemy) = (0..).filter_map(|i| { - room.maps.enemy_by_id(i).ok().and_then(|enemy| { - if enemy.monster == MonsterType::DarkFalz2 { - Some((i, enemy)) - } - else { - None - } - }) - }).next().unwrap(); - let map_enemy_stats = room.monster_stats.get(&map_enemy.monster).unwrap(); - (enemy_id, map_enemy_stats.exp) - })).await.unwrap(); - ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::RequestExp(RequestExp { - client: enemy_id as u8, + client: 0, target: 16, - enemy_id: enemy_id as u16, + enemy_id: 0, client_id: 0, unused: 0, last_hitter: 1, })))).await.unwrap(); ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::RequestExp(RequestExp { - client: enemy_id as u8, + client: 0, target: 16, - enemy_id: enemy_id as u16, + enemy_id: 0, client_id: 0, unused: 0, last_hitter: 0, })))).await.unwrap(); ship.clients.with(ClientId(1), |client| Box::pin(async move { - assert!(client.character.exp == exp); + assert_eq!(client.character.exp, 13); })).await.unwrap(); ship.clients.with(ClientId(2), |client| Box::pin(async move { - assert!(client.character.exp == (exp as f32 * 0.8) as u32); + assert_eq!(client.character.exp, 10); })).await.unwrap(); } -- 2.36.0 From 58da1f87f6827bd52d54a66d5952769ae55a4c63 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 15:31:49 -0700 Subject: [PATCH 11/30] inital drop test --- src/ship/drops/mod.rs | 76 ++++++++++++++++++- src/ship/drops/rare_drop_table.rs | 90 ++++++++++++++++++----- src/ship/packet/handler/direct_message.rs | 1 - tests/test_item_drop.rs | 76 +++++++++++++++++++ 4 files changed, 223 insertions(+), 20 deletions(-) create mode 100644 tests/test_item_drop.rs diff --git a/src/ship/drops/mod.rs b/src/ship/drops/mod.rs index e4f695d..9c20130 100644 --- a/src/ship/drops/mod.rs +++ b/src/ship/drops/mod.rs @@ -6,7 +6,7 @@ mod drop_table; -mod rare_drop_table; +pub mod rare_drop_table; mod generic_weapon; mod generic_armor; mod generic_shield; @@ -141,6 +141,20 @@ impl DropTable { } } + pub fn builder() -> DropTableBuilder { + DropTableBuilder { + monster_stats: None, + rare_table: None, + weapon_table: None, + armor_table: None, + shield_table: None, + unit_table: None, + tool_table: None, + box_table: None, + rng: None, + } + } + fn generate_meseta(&mut self, monster: &MonsterDropStats) -> Option { Some(ItemDropType::Meseta(self.rng.gen_range(monster.min_meseta, monster.max_meseta + 1))) } @@ -189,6 +203,66 @@ impl DropTable { } +pub struct DropTableBuilder { + monster_stats: Option>, + rare_table: Option, + weapon_table: Option, + armor_table: Option, + shield_table: Option, + unit_table: Option, + tool_table: Option, + box_table: Option, + rng: Option, +} + +// TODO: add the rest of these later I just need these ones right now +impl DropTableBuilder { + #[must_use] + pub fn monster_stats(mut self, monster_stats: HashMap) -> DropTableBuilder { + self.monster_stats = Some(monster_stats); + self + } + + #[must_use] + pub fn monster_stat(mut self, monster_type: MonsterType, drop_stats: MonsterDropStats) -> DropTableBuilder { + match &mut self.monster_stats { + Some(monster_stats) => { + monster_stats.insert(monster_type, drop_stats); + }, + None => { + let mut monster_stats = HashMap::default(); + monster_stats.insert(monster_type, drop_stats); + self.monster_stats = Some(monster_stats); + } + } + self + } + + #[must_use] + pub fn rare_table(mut self, rare_table: RareDropTable) -> DropTableBuilder { + self.rare_table = Some(rare_table); + self + } + + pub fn build(self, episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable { + DropTable { + monster_stats: self.monster_stats.unwrap_or_else(|| { + let monster_stats: HashMap = load_data_file(episode, difficulty, section_id, "monster_dar.toml"); + monster_stats.into_iter().map(|(m, s)| (m.parse().unwrap(), s)).collect() + }), + rare_table: self.rare_table.unwrap_or_else(|| RareDropTable::new(episode, difficulty, section_id)), + weapon_table: self.weapon_table.unwrap_or_else(|| GenericWeaponTable::new(episode, difficulty, section_id)), + armor_table: self.armor_table.unwrap_or_else(|| GenericArmorTable::new(episode, difficulty, section_id)), + shield_table: self.shield_table.unwrap_or_else(|| GenericShieldTable::new(episode, difficulty, section_id)), + unit_table: self.unit_table.unwrap_or_else(|| GenericUnitTable::new(episode, difficulty, section_id)), + tool_table: self.tool_table.unwrap_or_else(|| ToolTable::new(episode, difficulty, section_id)), + box_table: self.box_table.unwrap_or_else(|| BoxDropTable::new(episode, difficulty, section_id)), + rng: self.rng.unwrap_or_else(|| rand_chacha::ChaCha20Rng::from_entropy()), + } + } +} + + #[cfg(test)] mod test { use super::*; diff --git a/src/ship/drops/rare_drop_table.rs b/src/ship/drops/rare_drop_table.rs index 5d5f4c8..51151ba 100644 --- a/src/ship/drops/rare_drop_table.rs +++ b/src/ship/drops/rare_drop_table.rs @@ -50,9 +50,9 @@ impl RareDropItem { } -struct RareDropRate { - rate: f32, - item: RareDropItem +pub struct RareDropRate { + pub rate: f32, + pub item: RareDropItem } @@ -71,30 +71,41 @@ pub struct RareDropTable { shield_stats: GenericShieldTable, } -impl RareDropTable { - pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> RareDropTable { - let cfg: HashMap> = load_data_file(episode, difficulty, section_id, "rare_rate.toml"); - - let rates = cfg.into_iter() - .map(|(monster, drops)| { - let monster = monster.parse().unwrap(); - let drops = drops.into_iter().map(|drop| { - RareDropRate { - rate: drop.rate, - item: RareDropItem::from_string(drop.item), - } - }).collect(); - (monster, drops) +fn load_default_monster_rates(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> HashMap> { + let cfg: HashMap> = load_data_file(episode, difficulty, section_id, "rare_rate.toml"); + + cfg.into_iter() + .map(|(monster, drops)| { + let monster = monster.parse().unwrap(); + let drops = drops.into_iter().map(|drop| { + RareDropRate { + rate: drop.rate, + item: RareDropItem::from_string(drop.item), + } }).collect(); + (monster, drops) + }).collect() +} +impl RareDropTable { + pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> RareDropTable { RareDropTable { - rates, + rates: load_default_monster_rates(episode, difficulty, section_id), attribute_table: AttributeTable::new(episode, difficulty, section_id), armor_stats: GenericArmorTable::new(episode, difficulty, section_id), shield_stats: GenericShieldTable::new(episode, difficulty, section_id), } } + pub fn builder() -> RareDropTableBuilder { + RareDropTableBuilder { + rates: None, + attribute_table: None, + armor_stats: None, + shield_stats: None, + } + } + pub fn apply_item_stats(&self, map_area: &MapArea, item: RareDropItem, rng: &mut R) -> ItemDropType { match item { RareDropItem::Weapon(weapon) => { @@ -155,3 +166,46 @@ impl RareDropTable { }) } } + + +pub struct RareDropTableBuilder { + rates: Option>>, + attribute_table: Option, + armor_stats: Option, + shield_stats: Option, +} + + +// TODO: add the rest of these later I just need these ones right now +impl RareDropTableBuilder { + pub fn rates(mut self, rates: HashMap>) -> RareDropTableBuilder { + self.rates = Some(rates); + self + } + + #[must_use] + pub fn rate(mut self, monster_type: MonsterType, drop_rate: RareDropRate) -> RareDropTableBuilder { + match &mut self.rates { + Some(rates) => { + rates.entry(monster_type) + .or_insert(Vec::new()) + .push(drop_rate); + }, + None => { + let mut rates = HashMap::default(); + rates.insert(monster_type, vec![drop_rate]); + self.rates = Some(rates); + } + } + self + } + + pub fn build(self, episode: Episode, difficulty: Difficulty, section_id: SectionID) -> RareDropTable { + RareDropTable { + rates: self.rates.unwrap_or_else(|| load_default_monster_rates(episode, difficulty, section_id)), + attribute_table: self.attribute_table.unwrap_or_else(|| AttributeTable::new(episode, difficulty, section_id)), + armor_stats: self.armor_stats.unwrap_or_else(|| GenericArmorTable::new(episode, difficulty, section_id)), + shield_stats: self.shield_stats.unwrap_or_else(|| GenericShieldTable::new(episode, difficulty, section_id)), + } + } +} diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index 9b9455d..0f37837 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -209,7 +209,6 @@ where } 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 { clients_in_area.into_iter() .filter_map(move |area_client| { diff --git a/tests/test_item_drop.rs b/tests/test_item_drop.rs new file mode 100644 index 0000000..49cd75b --- /dev/null +++ b/tests/test_item_drop.rs @@ -0,0 +1,76 @@ +use elseware::common::serverstate::{ClientId, ServerState}; +use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; +use elseware::entity::character::SectionID; +use elseware::common::leveltable::CharacterLevelTable; +use elseware::ship::ship::{ShipServerState, SendShipPacket, RecvShipPacket}; +use elseware::ship::room::{Episode, Difficulty}; +use elseware::ship::monster::MonsterType; +use elseware::ship::location::RoomId; +use elseware::ship::drops::{DropTable, MonsterDropStats, MonsterDropType}; +use elseware::ship::drops::rare_drop_table::{RareDropTable, RareDropRate, RareDropItem}; +use elseware::ship::map::{Maps, MapVariant, MapArea, MapVariantMode, MapEnemy}; +use elseware::entity::item::weapon::WeaponType; + +use libpso::packet::ship::*; +use libpso::packet::messages::*; + +#[path = "common.rs"] +mod common; +use common::*; + +#[async_std::test] +async fn test_enemy_drops_item() { + let mut entity_gateway = InMemoryGateway::default(); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + + let mut ship = Box::new(ShipServerState::builder() + .gateway(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .drop_table_builder(Box::new(|episode, difficulty, section_id| { + DropTable::builder() + .monster_stat(MonsterType::Hildebear, MonsterDropStats { + dar: 100, + drop_type: MonsterDropType::Weapon, + min_meseta: 0, + max_meseta: 0, + }) + .rare_table(RareDropTable::builder() + .rate(MonsterType::Hildebear, RareDropRate { + rate: 1.0, + item: RareDropItem::Weapon(WeaponType::DarkFlow) + }) + .build(episode, difficulty, section_id)) + .build(episode, difficulty, section_id) + })) + .build()); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + create_room(&mut ship, ClientId(1), "room", "").await; + + let pkt = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::RequestItem(RequestItem { + client: 0, + target: 0, + map_area: 2, + pt_index: 0, + enemy_id: 0, + x: 0.0, + z: 0.0, + y: 0.0, + })))).await.unwrap(); + + match &pkt[0].1 { + SendShipPacket::Message(Message{msg: GameMessage::ItemDrop(item_drop)}) => { + assert_eq!(item_drop.item_id, 0x810001); + assert_eq!(item_drop.item_bytes[1], 0x9D); + }, + _ => panic!(), + } + + +} -- 2.36.0 From f80e37c4386c25d08139443c94e42d705d573630 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 15:32:09 -0700 Subject: [PATCH 12/30] oh forgot to add these migrations --- .../gateway/postgres/migrations/V0007__player_keyconfig.sql | 3 +++ .../gateway/postgres/migrations/V0008__playtime_not_null.sql | 5 +++++ 2 files changed, 8 insertions(+) create mode 100644 src/entity/gateway/postgres/migrations/V0007__player_keyconfig.sql create mode 100644 src/entity/gateway/postgres/migrations/V0008__playtime_not_null.sql diff --git a/src/entity/gateway/postgres/migrations/V0007__player_keyconfig.sql b/src/entity/gateway/postgres/migrations/V0007__player_keyconfig.sql new file mode 100644 index 0000000..23067d5 --- /dev/null +++ b/src/entity/gateway/postgres/migrations/V0007__player_keyconfig.sql @@ -0,0 +1,3 @@ +alter table player_character + add keyboard_config bytea not null, + add gamepad_config bytea not null; diff --git a/src/entity/gateway/postgres/migrations/V0008__playtime_not_null.sql b/src/entity/gateway/postgres/migrations/V0008__playtime_not_null.sql new file mode 100644 index 0000000..60e689b --- /dev/null +++ b/src/entity/gateway/postgres/migrations/V0008__playtime_not_null.sql @@ -0,0 +1,5 @@ +alter table player_character + drop column playtime; + +alter table player_character + add playtime integer not null; -- 2.36.0 From f5fea8540e79bfb1be7ecb7a64bd0fb72fe48a1c Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 15:57:58 -0700 Subject: [PATCH 13/30] fix problem where item drops were not pickup-able --- src/ship/packet/handler/direct_message.rs | 2 +- tests/test_item_drop.rs | 136 +++++++++++++++++++++- 2 files changed, 136 insertions(+), 2 deletions(-) diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index 0f37837..81f0146 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -117,7 +117,7 @@ where z: request_item.z, item: item_drop, }; - let character_id = clients.with(id, |client| Box::pin(async move { + let character_id = clients.with(area_client.client, |client| Box::pin(async move { client.character.id })).await?; diff --git a/tests/test_item_drop.rs b/tests/test_item_drop.rs index 49cd75b..02b01b1 100644 --- a/tests/test_item_drop.rs +++ b/tests/test_item_drop.rs @@ -71,6 +71,140 @@ async fn test_enemy_drops_item() { }, _ => panic!(), } - +} + +#[async_std::test] +async fn test_enemy_drops_item_for_two_players() { + let mut entity_gateway = InMemoryGateway::default(); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + + let mut ship = Box::new(ShipServerState::builder() + .gateway(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .drop_table_builder(Box::new(|episode, difficulty, section_id| { + DropTable::builder() + .monster_stat(MonsterType::Hildebear, MonsterDropStats { + dar: 100, + drop_type: MonsterDropType::Weapon, + min_meseta: 0, + max_meseta: 0, + }) + .rare_table(RareDropTable::builder() + .rate(MonsterType::Hildebear, RareDropRate { + rate: 1.0, + item: RareDropItem::Weapon(WeaponType::DarkFlow) + }) + .build(episode, difficulty, section_id)) + .build(episode, difficulty, section_id) + })) + .build()); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + log_in_char(&mut ship, ClientId(2), "a2", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + join_lobby(&mut ship, ClientId(2)).await; + create_room(&mut ship, ClientId(1), "room", "").await; + join_room(&mut ship, ClientId(2), 0).await; + + let pkt = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::RequestItem(RequestItem { + client: 0, + target: 0, + map_area: 2, + pt_index: 0, + enemy_id: 0, + x: 0.0, + z: 0.0, + y: 0.0, + })))).await.unwrap(); + + assert_eq!(pkt[0].0, ClientId(1)); + match &pkt[0].1 { + SendShipPacket::Message(Message{msg: GameMessage::ItemDrop(item_drop)}) => { + assert_eq!(item_drop.item_id, 0x810001); + assert_eq!(item_drop.item_bytes[1], 0x9D); + }, + _ => panic!(), + } + assert_eq!(pkt[1].0, ClientId(2)); + match &pkt[1].1 { + SendShipPacket::Message(Message{msg: GameMessage::ItemDrop(item_drop)}) => { + assert_eq!(item_drop.item_id, 0x810002); + assert_eq!(item_drop.item_bytes[1], 0x9D); + }, + _ => panic!(), + } +} + +#[async_std::test] +async fn test_enemy_drops_item_for_two_players_and_pick_up() { + let mut entity_gateway = InMemoryGateway::default(); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; + + let mut ship = Box::new(ShipServerState::builder() + .gateway(entity_gateway.clone()) + .map_builder(Box::new(|_room_mode, _event| { + Maps::new( + vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)], + vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))], + Vec::new(), + ) + })) + .drop_table_builder(Box::new(|episode, difficulty, section_id| { + DropTable::builder() + .monster_stat(MonsterType::Hildebear, MonsterDropStats { + dar: 100, + drop_type: MonsterDropType::Weapon, + min_meseta: 0, + max_meseta: 0, + }) + .rare_table(RareDropTable::builder() + .rate(MonsterType::Hildebear, RareDropRate { + rate: 1.0, + item: RareDropItem::Weapon(WeaponType::DarkFlow) + }) + .build(episode, difficulty, section_id)) + .build(episode, difficulty, section_id) + })) + .build()); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + log_in_char(&mut ship, ClientId(2), "a2", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + join_lobby(&mut ship, ClientId(2)).await; + create_room(&mut ship, ClientId(1), "room", "").await; + join_room(&mut ship, ClientId(2), 0).await; + + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::RequestItem(RequestItem { + client: 0, + target: 0, + map_area: 2, + pt_index: 0, + enemy_id: 0, + x: 0.0, + z: 0.0, + y: 0.0, + })))).await.unwrap(); + + ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { + client: 0, + target: 0, + item_id: 0x810002, + map_area: 0, + unknown: [0; 3] + })))).await.unwrap(); + + ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { + client: 0, + target: 0, + item_id: 0x810001, + map_area: 0, + unknown: [0; 3] + })))).await.unwrap(); } -- 2.36.0 From 0b641424da6138e3f223d663b694b7a88f5ae5fe Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 16:34:11 -0700 Subject: [PATCH 14/30] don't start with 300 meseta in bank --- src/login/character.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/login/character.rs b/src/login/character.rs index 928b4b2..7bc5ab8 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -211,7 +211,7 @@ async fn new_character(entity_gateway: &mut EG, user: let character = entity_gateway.create_character(character).await?; entity_gateway.set_character_meseta(&character.id, Meseta(300)).await?; - entity_gateway.set_bank_meseta(&character.id, &BankName("".into()), Meseta(300)).await?; + entity_gateway.set_bank_meseta(&character.id, &BankName("".into()), Meseta(0)).await?; let new_weapon = match character.char_class { CharacterClass::HUmar | CharacterClass::HUnewearl | CharacterClass::HUcast | CharacterClass::HUcaseal => item::weapon::WeaponType::Saber, -- 2.36.0 From fe472eaae218c3812ac9d6b906495e5592e3c21d Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 16:34:29 -0700 Subject: [PATCH 15/30] lvl value in level up pkt is 0-based --- src/ship/packet/handler/message.rs | 2 +- tests/test_exp_gain.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs index 36c97d6..f4e4d69 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -59,7 +59,7 @@ where let (_, before_stats) = LEVEL_TABLE.get_stats_from_exp(char_class, exp); let (after_level, after_stats) = LEVEL_TABLE.get_stats_from_exp(char_class, exp + exp_gain); - let level_up_pkt = builder::message::character_leveled_up(area_client, after_level, before_stats, after_stats); + let level_up_pkt = builder::message::character_leveled_up(area_client, after_level-1, before_stats, after_stats); exp_pkts.extend(clients_in_area.into_iter() .map(move |c| { (c.client, SendShipPacket::Message(Message::new(GameMessage::PlayerLevelUp(level_up_pkt.clone())))) diff --git a/tests/test_exp_gain.rs b/tests/test_exp_gain.rs index 465f949..0317e9d 100644 --- a/tests/test_exp_gain.rs +++ b/tests/test_exp_gain.rs @@ -81,7 +81,7 @@ async fn test_character_levels_up() { last_hitter: 1, })))).await.unwrap(); - assert!(matches!(levelup_pkt[1].1, SendShipPacket::Message(Message {msg: GameMessage::PlayerLevelUp(PlayerLevelUp {lvl: 2, ..})}))); + assert!(matches!(levelup_pkt[1].1, SendShipPacket::Message(Message {msg: GameMessage::PlayerLevelUp(PlayerLevelUp {lvl: 1, ..})}))); let leveltable = CharacterLevelTable::default(); ship.clients.with(ClientId(1), |client| Box::pin(async move { @@ -118,7 +118,7 @@ async fn test_character_levels_up_multiple_times() { last_hitter: 1, })))).await.unwrap(); - 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: 7, ..})}))); ship.clients.with(ClientId(1), |client| Box::pin(async move { assert!(3000 == client.character.exp); -- 2.36.0 From 31ebc1af3252115df31dda21a7ce07a9c3333230 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 17:06:48 -0700 Subject: [PATCH 16/30] actually store meseta bank interaction --- src/ship/items/actions.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ship/items/actions.rs b/src/ship/items/actions.rs index a9d974a..66a2c0b 100644 --- a/src/ship/items/actions.rs +++ b/src/ship/items/actions.rs @@ -245,6 +245,7 @@ where let mut bank = item_state.bank(&character_id).await?; bank.remove_meseta(amount)?; transaction.gateway().set_bank_meseta(&character_id, &bank.name, bank.meseta).await?; + item_state.set_bank(bank).await; Ok(((item_state, transaction), ())) }) @@ -286,6 +287,7 @@ where let mut bank = item_state.bank(&character_id).await?; bank.add_meseta(amount)?; transaction.gateway().set_bank_meseta(&character_id, &bank.name, bank.meseta).await?; + item_state.set_bank(bank).await; Ok(((item_state, transaction), ())) }) -- 2.36.0 From d495ec97f2e93548e7fc62854c2211192ca4e517 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 20:41:12 -0700 Subject: [PATCH 17/30] fix this keyconfig nonsense --- src/bin/main.rs | 4 +- src/entity/character.rs | 84 +------------------ src/entity/gateway/inmemory.rs | 2 - .../migrations/V0009__no_player_keyconfig.sql | 3 + src/entity/gateway/postgres/models.rs | 8 -- src/entity/gateway/postgres/postgres.rs | 15 ++-- src/login/character.rs | 2 +- src/ship/items/actions.rs | 2 +- src/ship/packet/handler/lobby.rs | 4 +- src/ship/packet/handler/settings.rs | 8 +- tests/common.rs | 3 +- tests/test_character.rs | 29 +------ 12 files changed, 25 insertions(+), 139 deletions(-) create mode 100644 src/entity/gateway/postgres/migrations/V0009__no_player_keyconfig.sql diff --git a/src/bin/main.rs b/src/bin/main.rs index eb7c687..2b262fc 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -64,12 +64,12 @@ fn main() { }; let fake_user = entity_gateway.create_user(fake_user).await.unwrap(); entity_gateway.create_user_settings(NewUserSettingsEntity::new(fake_user.id)).await.unwrap(); - let mut character = NewCharacterEntity::new(fake_user.id, 1); + let mut character = NewCharacterEntity::new(fake_user.id); character.name = format!("Test Char {}", i*2); let character = entity_gateway.create_character(character).await.unwrap(); entity_gateway.set_character_meseta(&character.id, item::Meseta(999999)).await.unwrap(); entity_gateway.set_bank_meseta(&character.id, &item::BankName("".into()), item::Meseta(999999)).await.unwrap(); - let mut character = NewCharacterEntity::new(fake_user.id, 1); + let mut character = NewCharacterEntity::new(fake_user.id); character.slot = 2; character.name = "ItemRefactor".into(); character.exp = 80000000; diff --git a/src/entity/character.rs b/src/entity/character.rs index bb5a6d0..8b6c4e8 100644 --- a/src/entity/character.rs +++ b/src/entity/character.rs @@ -264,82 +264,6 @@ pub struct CharacterMaterials { pub tp: u32, } -#[derive(Clone, Debug)] -pub struct CharacterKeyboardConfig { - pub keyboard_config: [u8; 0x16C], -} - -impl Default for CharacterKeyboardConfig { - fn default() -> CharacterKeyboardConfig { - CharacterKeyboardConfig { - keyboard_config: DEFAULT_KEYBOARD_CONFIG1, - } - } -} - -impl CharacterKeyboardConfig { - fn new(preset: usize) -> CharacterKeyboardConfig { - match preset { - 1 => { - CharacterKeyboardConfig { - keyboard_config: DEFAULT_KEYBOARD_CONFIG1, - } - }, - 2 => { - CharacterKeyboardConfig { - keyboard_config: DEFAULT_KEYBOARD_CONFIG2, - } - }, - 3 => { - CharacterKeyboardConfig { - keyboard_config: DEFAULT_KEYBOARD_CONFIG3, - } - }, - 4 => { - CharacterKeyboardConfig { - keyboard_config: DEFAULT_KEYBOARD_CONFIG4, - } - }, - _ => { - CharacterKeyboardConfig { - keyboard_config: DEFAULT_KEYBOARD_CONFIG1, - } - }, - } - } - - pub fn update(&mut self, new_config: &KeyboardConfig) { - self.keyboard_config = new_config.keyboard_config; - } - - pub fn as_bytes(&self) -> [u8; 0x16C] { - self.keyboard_config - } -} - -#[derive(Clone, Debug)] -pub struct CharacterGamepadConfig { - pub gamepad_config: [u8; 0x38], -} - -impl Default for CharacterGamepadConfig { - fn default() -> CharacterGamepadConfig { - CharacterGamepadConfig { - gamepad_config: DEFAULT_GAMEPAD_CONFIG, - } - } -} - -impl CharacterGamepadConfig { - pub fn update(&mut self, new_config: &GamepadConfig) { - self.gamepad_config = new_config.gamepad_config; - } - - pub fn as_bytes(&self) -> [u8; 0x38] { - self.gamepad_config - } -} - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Default, derive_more::Display)] pub struct CharacterEntityId(pub u32); @@ -363,12 +287,10 @@ pub struct NewCharacterEntity { pub tech_menu: CharacterTechMenu, pub option_flags: u32, - pub keyboard_config: CharacterKeyboardConfig, - pub gamepad_config: CharacterGamepadConfig, } impl NewCharacterEntity { - pub fn new(user: UserAccountId, keyboard_config_preset: usize,) -> NewCharacterEntity { + pub fn new(user: UserAccountId) -> NewCharacterEntity { NewCharacterEntity { user_id: user, slot: 0, @@ -384,8 +306,6 @@ impl NewCharacterEntity { materials: CharacterMaterials::default(), tech_menu: CharacterTechMenu::default(), option_flags: 0, - keyboard_config: CharacterKeyboardConfig::new(keyboard_config_preset), - gamepad_config: CharacterGamepadConfig::default(), } } } @@ -411,8 +331,6 @@ pub struct CharacterEntity { pub tech_menu: CharacterTechMenu, pub option_flags: u32, - pub keyboard_config: CharacterKeyboardConfig, - pub gamepad_config: CharacterGamepadConfig, pub playtime: u32, } diff --git a/src/entity/gateway/inmemory.rs b/src/entity/gateway/inmemory.rs index 9e4a9a0..07fd186 100644 --- a/src/entity/gateway/inmemory.rs +++ b/src/entity/gateway/inmemory.rs @@ -452,8 +452,6 @@ impl EntityGateway for InMemoryGateway { materials: character.materials, tech_menu: character.tech_menu, option_flags: character.option_flags, - keyboard_config: character.keyboard_config, - gamepad_config: character.gamepad_config, playtime: 0, }; characters.insert(new_character.id, new_character.clone()); diff --git a/src/entity/gateway/postgres/migrations/V0009__no_player_keyconfig.sql b/src/entity/gateway/postgres/migrations/V0009__no_player_keyconfig.sql new file mode 100644 index 0000000..b70d210 --- /dev/null +++ b/src/entity/gateway/postgres/migrations/V0009__no_player_keyconfig.sql @@ -0,0 +1,3 @@ +alter table player_character + drop column keyboard_config, + drop column gamepad_config; diff --git a/src/entity/gateway/postgres/models.rs b/src/entity/gateway/postgres/models.rs index 5350964..fd4980b 100644 --- a/src/entity/gateway/postgres/models.rs +++ b/src/entity/gateway/postgres/models.rs @@ -217,8 +217,6 @@ pub struct PgCharacter { tp: i16, tech_menu: Vec, - keyboard_config: Vec, - gamepad_config: Vec, playtime: i32, } @@ -270,12 +268,6 @@ impl From for CharacterEntity { tech_menu: CharacterTechMenu { tech_menu: vec_to_array(other.tech_menu) }, - keyboard_config: CharacterKeyboardConfig { - keyboard_config: vec_to_array(other.keyboard_config) - }, - gamepad_config: CharacterGamepadConfig { - gamepad_config: vec_to_array(other.gamepad_config) - }, playtime: other.playtime as u32, } } diff --git a/src/entity/gateway/postgres/postgres.rs b/src/entity/gateway/postgres/postgres.rs index 0016487..5ec3ffd 100644 --- a/src/entity/gateway/postgres/postgres.rs +++ b/src/entity/gateway/postgres/postgres.rs @@ -229,8 +229,7 @@ async fn create_character(conn: &mut sqlx::PgConnection, char: NewCharacterEntit hair, hair_r, hair_g, hair_b, prop_x, prop_y, techs, config, infoboard, guildcard, power, mind, def, evade, luck, - hp, tp, tech_menu, option_flags, keyboard_config, - gamepad_config, playtime) + hp, tp, tech_menu, option_flags, playtime) values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, @@ -270,8 +269,6 @@ async fn create_character(conn: &mut sqlx::PgConnection, char: NewCharacterEntit .bind(char.materials.tp as i16) .bind(char.tech_menu.tech_menu.to_vec()) .bind(char.option_flags as i32) - .bind(&char.keyboard_config.keyboard_config.to_vec()) - .bind(&char.gamepad_config.gamepad_config.to_vec()) .bind(0) .fetch_one(conn).await?; @@ -298,8 +295,8 @@ async fn save_character(conn: &mut sqlx::PgConnection, char: &CharacterEntity) - let q = r#"update player_character set user_account=$1, slot=$2, name=$3, exp=$4, class=$5, section_id=$6, costume=$7, skin=$8, face=$9, head=$10, hair=$11, hair_r=$12, hair_g=$13, hair_b=$14, prop_x=$15, prop_y=$16, techs=$17, config=$18, infoboard=$19, guildcard=$20, power=$21, mind=$22, def=$23, - evade=$24, luck=$25, hp=$26, tp=$27, tech_menu=$28, option_flags=$29, keyboard_config=$30, gamepad_config=$31, playtime=$32 - where id=$33;"#; + evade=$24, luck=$25, hp=$26, tp=$27, tech_menu=$28, option_flags=$29, playtime=$30 + where id=$31;"#; sqlx::query(q) .bind(char.user_id.0) // $1 .bind(char.slot as i16) // $2 @@ -330,10 +327,8 @@ async fn save_character(conn: &mut sqlx::PgConnection, char: &CharacterEntity) - .bind(char.materials.tp as i16) // $27 .bind(char.tech_menu.tech_menu.to_vec()) // $28 .bind(char.option_flags as i32) // $29 - .bind(&char.keyboard_config.keyboard_config.to_vec()) // $30 - .bind(&char.gamepad_config.gamepad_config.to_vec()) // $31 - .bind(char.playtime as i32) // $32 - .bind(char.id.0 as i32) // $33 + .bind(char.playtime as i32) // $30 + .bind(char.id.0 as i32) // $31 .execute(conn).await?; Ok(()) } diff --git a/src/login/character.rs b/src/login/character.rs index 7bc5ab8..cd6bb65 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -747,7 +747,7 @@ impl InterserverActor for CharacterServerState { fn new_character_from_preview(user: &UserAccountEntity, preview: &CharacterPreview) -> NewCharacterEntity { - let mut character = NewCharacterEntity::new(user.id, 1); // it should not be possible for the client to specify the kbm config preset from the char create screen + let mut character = NewCharacterEntity::new(user.id); character.slot = preview.slot; character.name = String::from_utf16_lossy(&preview.character.name).trim_matches(char::from(0)).into(); character.section_id = preview.character.section_id.into(); diff --git a/src/ship/items/actions.rs b/src/ship/items/actions.rs index 66a2c0b..2d41151 100644 --- a/src/ship/items/actions.rs +++ b/src/ship/items/actions.rs @@ -113,7 +113,7 @@ where move |(mut item_state, mut transaction), _| { Box::pin(async move { let mut inventory = item_state.inventory(&character_id).await?; - let item = inventory.take_item(&item_id, amount).ok_or_else(|| ItemStateError::NoFloorItem(item_id))?; + let item = inventory.take_item(&item_id, amount).ok_or_else(|| ItemStateError::NoInventoryItem(item_id))?; transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?; item_state.set_inventory(inventory).await; diff --git a/src/ship/packet/handler/lobby.rs b/src/ship/packet/handler/lobby.rs index bfafe86..9d7ca08 100644 --- a/src/ship/packet/handler/lobby.rs +++ b/src/ship/packet/handler/lobby.rs @@ -34,8 +34,8 @@ pub async fn block_selected(id: ClientId, .meseta(inventory.meseta) .inventory(&inventory) .bank(&bank) - .keyboard_config(&client.character.keyboard_config.as_bytes()) - .gamepad_config(&client.character.gamepad_config.as_bytes()) + .keyboard_config(&client.settings.settings.keyboard_config) + .gamepad_config(&client.settings.settings.gamepad_config) .symbol_chat(&client.settings.settings.symbol_chats) .tech_menu(&client.character.tech_menu.as_bytes()) .option_flags(client.character.option_flags) diff --git a/src/ship/packet/handler/settings.rs b/src/ship/packet/handler/settings.rs index d2b2500..3566b69 100644 --- a/src/ship/packet/handler/settings.rs +++ b/src/ship/packet/handler/settings.rs @@ -48,8 +48,8 @@ where clients.with_mut(id, |client| { let mut entity_gateway = entity_gateway.clone(); Box::pin(async move { - client.character.keyboard_config.update(&keyboard_config); - entity_gateway.save_character(&client.character).await + client.settings.settings.keyboard_config = keyboard_config.keyboard_config; + entity_gateway.save_user_settings(&client.settings).await })}).await??; Ok(Vec::new()) } @@ -65,8 +65,8 @@ where clients.with_mut(id, |client| { let mut entity_gateway = entity_gateway.clone(); Box::pin(async move { - client.character.gamepad_config.update(&gamepad_config); - entity_gateway.save_character(&client.character).await + client.settings.settings.gamepad_config = gamepad_config.gamepad_config; + entity_gateway.save_user_settings(&client.settings).await })}).await??; Ok(Vec::new()) } diff --git a/tests/common.rs b/tests/common.rs index d2ea567..1a8a6a0 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -13,6 +13,7 @@ use libpso::packet::login::{Login, Session}; use libpso::{utf8_to_array, utf8_to_utf16_array}; +//TODO: remove kb_conf_preset pub async fn new_user_character(entity_gateway: &mut EG, username: &str, password: &str, kb_conf_preset: usize) -> (UserAccountEntity, CharacterEntity) { let new_user = NewUserAccountEntity { email: format!("{}@pso.com", username), @@ -26,7 +27,7 @@ pub async fn new_user_character(entity_gateway: &mut let user = entity_gateway.create_user(new_user).await.unwrap(); let new_settings = NewUserSettingsEntity::new(user.id); let _settings = entity_gateway.create_user_settings(new_settings).await.unwrap(); - let new_character = NewCharacterEntity::new(user.id, kb_conf_preset); + let new_character = NewCharacterEntity::new(user.id); let character = entity_gateway.create_character(new_character).await.unwrap(); entity_gateway.set_character_meseta(&character.id, Meseta(0)).await.unwrap(); entity_gateway.set_bank_meseta(&character.id, &BankName("".into()), Meseta(0)).await.unwrap(); diff --git a/tests/test_character.rs b/tests/test_character.rs index 29812e9..ca16eac 100644 --- a/tests/test_character.rs +++ b/tests/test_character.rs @@ -31,26 +31,6 @@ async fn test_save_options() { assert!(char.option_flags == 12345); } -#[async_std::test] -async fn test_default3_keyboard_mappings() { - /* - check if keyboard is set to default3 when specified. this will only occur for things like creating characters from the web page. - normal client behaviour will simply use default1 when creating a character. - gamepad only has 1 default config - */ - let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 3).await; - assert!(char1.keyboard_config.as_bytes() == DEFAULT_KEYBOARD_CONFIG3); -} - -#[async_std::test] -async fn test_invalid_keyboard_preset_value() { - // check if keyboard_config self-corrects to DEFAULT1 if an invalid value (>4) is given - let mut entity_gateway = InMemoryGateway::default(); - let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 10).await; - assert!(char1.keyboard_config.as_bytes() == DEFAULT_KEYBOARD_CONFIG1); -} - #[async_std::test] async fn test_change_keyboard_mappings() { let mut entity_gateway = InMemoryGateway::default(); @@ -63,7 +43,8 @@ async fn test_change_keyboard_mappings() { log_in_char(&mut ship, ClientId(1), "a1", "a").await; join_lobby(&mut ship, ClientId(1)).await; - assert!(char1.keyboard_config.as_bytes() == DEFAULT_KEYBOARD_CONFIG2); + let settings = entity_gateway.get_user_settings_by_user(&user1).await.unwrap(); + assert!(settings.settings.keyboard_config == DEFAULT_KEYBOARD_CONFIG1); // update from default2 to default4 // the client simply sends the full 364 bytes... @@ -95,8 +76,6 @@ async fn test_change_keyboard_mappings() { ], })).await.unwrap(); - let characters = entity_gateway.get_characters_by_user(&user1).await.unwrap(); - let char = characters[0].as_ref().unwrap(); - - assert!(char.keyboard_config.as_bytes() == DEFAULT_KEYBOARD_CONFIG4); + let settings = entity_gateway.get_user_settings_by_user(&user1).await.unwrap(); + assert!(settings.settings.keyboard_config == DEFAULT_KEYBOARD_CONFIG4); } -- 2.36.0 From f09c73611f2ae800b585240391da91a054f6f18e Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 22:15:29 -0700 Subject: [PATCH 18/30] fix some user setting entity stuff --- src/entity/gateway/inmemory.rs | 10 ++++++++++ src/entity/gateway/postgres/postgres.rs | 5 ++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/entity/gateway/inmemory.rs b/src/entity/gateway/inmemory.rs index 07fd186..88636ec 100644 --- a/src/entity/gateway/inmemory.rs +++ b/src/entity/gateway/inmemory.rs @@ -72,6 +72,10 @@ impl EntityGateway for InMemoryGatewayTransaction { } } + async fn save_user_settings(&mut self, settings: &UserSettingsEntity) -> Result<(), GatewayError> { + self.original_gateway.save_user_settings(settings).await + } + async fn save_character(&mut self, char: &CharacterEntity) -> Result<(), GatewayError> { copy_if_needed(&mut *self.working_gateway.characters.lock().await, &*self.original_gateway.characters.lock().await, @@ -418,6 +422,12 @@ impl EntityGateway for InMemoryGateway { .ok_or(GatewayError::Error) } + async fn save_user_settings(&mut self, settings: &UserSettingsEntity) -> Result<(), GatewayError> { + let mut user_settings = self.user_settings.lock().await; + user_settings.insert(settings.id, settings.clone()); + Ok(()) + } + async fn get_characters_by_user(&mut self, user: &UserAccountEntity) -> Result<[Option; 4], GatewayError> { let characters = self.characters.lock().await; const NONE: Option = None; diff --git a/src/entity/gateway/postgres/postgres.rs b/src/entity/gateway/postgres/postgres.rs index 5ec3ffd..ba77827 100644 --- a/src/entity/gateway/postgres/postgres.rs +++ b/src/entity/gateway/postgres/postgres.rs @@ -217,7 +217,7 @@ async fn save_user_settings(conn: &mut sqlx::PgConnection, settings: &UserSettin .bind(&settings.settings.symbol_chats.to_vec()) .bind(settings.settings.team_name.iter().copied().flat_map(|i| i.to_le_bytes().to_vec()).collect::>()) .bind(settings.id.0) - .fetch_one(conn).await?; + .execute(conn).await?; Ok(()) } @@ -236,8 +236,7 @@ async fn create_character(conn: &mut sqlx::PgConnection, char: NewCharacterEntit $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, - $26, $27, $28, $29, $30, - $31, $32) + $26, $27, $28, $29, $30) returning *;"#; let character = sqlx::query_as::<_, PgCharacter>(q) .bind(char.user_id.0) -- 2.36.0 From 7bd385d580992f4e575362918a59ef7740ac2505 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 22:15:49 -0700 Subject: [PATCH 19/30] anyhowing continues --- src/ship/items/bank.rs | 20 +++++++++--------- src/ship/items/floor.rs | 6 +++--- src/ship/items/inventory.rs | 42 ++++++++++++++++++------------------- src/ship/items/state.rs | 2 ++ 4 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/ship/items/bank.rs b/src/ship/items/bank.rs index 5abef95..5494102 100644 --- a/src/ship/items/bank.rs +++ b/src/ship/items/bank.rs @@ -64,10 +64,10 @@ pub struct BankItem { } impl BankItem { - pub async fn with_entity_id(&self, mut param: T, mut func: F) -> Result + pub async fn with_entity_id(&self, mut param: T, mut func: F) -> Result where F: FnMut(T, ItemEntityId) -> Fut, - Fut: Future>, + Fut: Future>, { match &self.item { BankItemDetail::Individual(individual_item) => { @@ -125,27 +125,27 @@ impl BankState { self.item_id_counter = base_item_id + self.bank.0.len() as u32; } - pub fn add_meseta(&mut self, amount: u32) -> Result<(), ItemStateError> { + pub fn add_meseta(&mut self, amount: u32) -> Result<(), anyhow::Error> { if self.meseta.0 + amount > 999999 { - return Err(ItemStateError::FullOfMeseta) + return Err(ItemStateError::FullOfMeseta.into()) } self.meseta.0 += amount; Ok(()) } - pub fn remove_meseta(&mut self, amount: u32) -> Result<(), ItemStateError> { + pub fn remove_meseta(&mut self, amount: u32) -> Result<(), anyhow::Error> { if amount > self.meseta.0 { - return Err(ItemStateError::InvalidMesetaRemoval(amount)) + return Err(ItemStateError::InvalidMesetaRemoval(amount).into()) } self.meseta.0 -= amount; Ok(()) } - pub fn add_inventory_item(&mut self, item: InventoryItem) -> Result { + pub fn add_inventory_item(&mut self, item: InventoryItem) -> Result { match item.item { InventoryItemDetail::Individual(iitem) => { if self.bank.0.len() >= 30 { - Err(BankError::BankFull) + Err(BankError::BankFull.into()) } else { self.bank.0.push(BankItem { @@ -166,7 +166,7 @@ impl BankState { match existing_stack { Some(existing_stack) => { if existing_stack.entity_ids.len() + sitem.entity_ids.len() > sitem.tool.max_stack() { - Err(BankError::StackFull) + Err(BankError::StackFull.into()) } else { existing_stack.entity_ids.append(&mut sitem.entity_ids.clone()); @@ -175,7 +175,7 @@ impl BankState { }, None => { if self.bank.0.len() >= 30 { - Err(BankError::BankFull) + Err(BankError::BankFull.into()) } else { self.bank.0.push(BankItem { diff --git a/src/ship/items/floor.rs b/src/ship/items/floor.rs index 2aab742..c71b7fd 100644 --- a/src/ship/items/floor.rs +++ b/src/ship/items/floor.rs @@ -33,7 +33,7 @@ pub struct FloorItem { } impl FloorItem { - pub async fn with_entity_id(&self, mut param: T, mut func: F) -> Result + pub async fn with_entity_id(&self, mut param: T, mut func: F) -> Result where F: FnMut(T, ItemEntityId) -> Fut, Fut: Future>, @@ -53,10 +53,10 @@ impl FloorItem { Ok(param) } - pub async fn with_mag(&self, mut param: T, mut func: F) -> Result + pub async fn with_mag(&self, mut param: T, mut func: F) -> Result where F: FnMut(T, ItemEntityId, Mag) -> Fut, - Fut: Future>, + Fut: Future>, { if let FloorItemDetail::Individual(individual_item) = &self.item { if let ItemDetail::Mag(mag) = &individual_item.item { diff --git a/src/ship/items/inventory.rs b/src/ship/items/inventory.rs index e10a808..bfd709b 100644 --- a/src/ship/items/inventory.rs +++ b/src/ship/items/inventory.rs @@ -60,7 +60,7 @@ impl InventoryItemDetail { } // TODO: this should probably go somewhere a bit more fundamental like ItemDetail - pub fn sell_price(&self) -> Result { + pub fn sell_price(&self) -> Result { match self { InventoryItemDetail::Individual(individual_item) => { match &individual_item.item { @@ -102,7 +102,7 @@ impl InventoryItemDetail { Ok((ToolShopItem::from(d).price() / 8) as u32) }, ItemDetail::Mag(_m) => { - Err(ItemStateError::ItemNotSellable) + Err(ItemStateError::ItemNotSellable.into()) }, ItemDetail::ESWeapon(_e) => { Ok(10u32) @@ -126,10 +126,10 @@ pub struct InventoryItem { } impl InventoryItem { - pub async fn with_entity_id(&self, mut param: T, mut func: F) -> Result + pub async fn with_entity_id(&self, mut param: T, mut func: F) -> Result where F: FnMut(T, ItemEntityId) -> Fut, - Fut: Future>, + Fut: Future>, { match &self.item { InventoryItemDetail::Individual(individual_item) => { @@ -145,10 +145,10 @@ impl InventoryItem { Ok(param) } - pub async fn with_mag(&self, mut param: T, mut func: F) -> Result + pub async fn with_mag(&self, mut param: T, mut func: F) -> Result where F: FnMut(T, ItemEntityId, Mag) -> Fut, - Fut: Future>, + Fut: Future>, { if let InventoryItemDetail::Individual(individual_item) = &self.item { if let ItemDetail::Mag(mag) = &individual_item.item { @@ -205,11 +205,11 @@ impl InventoryState { self.inventory.0.len() } - pub fn add_floor_item(&mut self, item: FloorItem) -> Result { + pub fn add_floor_item(&mut self, item: FloorItem) -> Result { match item.item { FloorItemDetail::Individual(iitem) => { if self.inventory.0.len() >= 30 { - Err(InventoryError::InventoryFull) + Err(InventoryError::InventoryFull.into()) } else { self.inventory.0.push(InventoryItem { @@ -229,7 +229,7 @@ impl InventoryState { match existing_stack { Some(existing_stack) => { if existing_stack.entity_ids.len() + sitem.entity_ids.len() > sitem.tool.max_stack() { - Err(InventoryError::StackFull) + Err(InventoryError::StackFull.into()) } else { existing_stack.entity_ids.append(&mut sitem.entity_ids.clone()); @@ -238,7 +238,7 @@ impl InventoryState { }, None => { if self.inventory.0.len() >= 30 { - Err(InventoryError::InventoryFull) + Err(InventoryError::InventoryFull.into()) } else { self.inventory.0.push(InventoryItem { @@ -253,7 +253,7 @@ impl InventoryState { }, FloorItemDetail::Meseta(meseta) => { if self.meseta == Meseta(999999) { - Err(InventoryError::MesetaFull) + Err(InventoryError::MesetaFull.into()) } else { self.meseta.0 = std::cmp::min(self.meseta.0 + meseta.0, 999999); @@ -263,11 +263,11 @@ impl InventoryState { } } - pub fn add_item(&mut self, item: InventoryItem) -> Result<(AddItemResult, InventoryItem), InventoryError> { + pub fn add_item(&mut self, item: InventoryItem) -> Result<(AddItemResult, InventoryItem), anyhow::Error> { match &item.item { InventoryItemDetail::Individual(_) => { if self.inventory.0.len() >= 30 { - Err(InventoryError::InventoryFull) + Err(InventoryError::InventoryFull.into()) } else { self.inventory.0.push(item); @@ -290,7 +290,7 @@ impl InventoryState { match existing_stack { Some(existing_stack) => { if existing_stack.entity_ids.len() + sitem.entity_ids.len() > sitem.tool.max_stack() { - Err(InventoryError::StackFull) + Err(InventoryError::StackFull.into()) } else { existing_stack.entity_ids.append(&mut sitem.entity_ids.clone()); @@ -307,7 +307,7 @@ impl InventoryState { }, None => { if self.inventory.0.len() >= 30 { - Err(InventoryError::InventoryFull) + Err(InventoryError::InventoryFull.into()) } else { self.inventory.0.push(item); @@ -370,25 +370,25 @@ impl InventoryState { .find(|i| i.item_id == *item_id) } - pub fn add_meseta(&mut self, amount: u32) -> Result<(), ItemStateError> { + pub fn add_meseta(&mut self, amount: u32) -> Result<(), anyhow::Error> { if self.meseta.0 == 999999 { - return Err(ItemStateError::FullOfMeseta) + return Err(ItemStateError::FullOfMeseta.into()) } self.meseta.0 = std::cmp::min(self.meseta.0 + amount, 999999); Ok(()) } - pub fn add_meseta_no_overflow(&mut self, amount: u32) -> Result<(), ItemStateError> { + pub fn add_meseta_no_overflow(&mut self, amount: u32) -> Result<(), anyhow::Error> { if self.meseta.0 + amount > 999999 { - return Err(ItemStateError::FullOfMeseta) + return Err(ItemStateError::FullOfMeseta.into()) } self.meseta.0 += amount; Ok(()) } - pub fn remove_meseta(&mut self, amount: u32) -> Result<(), ItemStateError> { + pub fn remove_meseta(&mut self, amount: u32) -> Result<(), anyhow::Error> { if amount > self.meseta.0 { - return Err(ItemStateError::InvalidMesetaRemoval(amount)) + return Err(ItemStateError::InvalidMesetaRemoval(amount).into()) } self.meseta.0 -= amount; Ok(()) diff --git a/src/ship/items/state.rs b/src/ship/items/state.rs index 44df7f9..1267b1b 100644 --- a/src/ship/items/state.rs +++ b/src/ship/items/state.rs @@ -22,6 +22,8 @@ pub enum ItemStateError { NoCharacter(CharacterEntityId), #[error("room {0} not found")] NoRoom(RoomId), + #[error("inventory item {0} not found")] + NoInventoryItem(ClientItemId), #[error("floor item {0} not found")] NoFloorItem(ClientItemId), #[error("expected {0} to be a tool")] -- 2.36.0 From 13c6592438b782a70cf0aaf2cd36bc2b98864b7b Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 23:05:42 -0700 Subject: [PATCH 20/30] you can use techs now wow --- src/entity/character.rs | 8 ++-- src/ship/items/apply_item.rs | 27 +++++++++-- tests/test_item_use.rs | 87 ++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 8 deletions(-) diff --git a/src/entity/character.rs b/src/entity/character.rs index 8b6c4e8..ddf892a 100644 --- a/src/entity/character.rs +++ b/src/entity/character.rs @@ -157,7 +157,7 @@ pub struct CharacterAppearance { } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct TechLevel(pub u8); #[derive(Clone, Debug, Default)] @@ -167,16 +167,14 @@ pub struct CharacterTechniques { impl CharacterTechniques { pub fn set_tech(&mut self, tech: Technique, level: TechLevel) { - self.techs.insert(tech, TechLevel(level.0 - 1)); + self.techs.insert(tech, TechLevel(level.0)); } - // from_bytes - pub fn as_bytes(&self) -> [u8; 20] { self.techs.iter() .fold([0xFF; 20], |mut techlist, (tech, level)| { let index = tech.as_value(); - techlist[index as usize] = level.0; + techlist[index as usize] = level.0 - 1; techlist }) } diff --git a/src/ship/items/apply_item.rs b/src/ship/items/apply_item.rs index bd01ecf..c418645 100644 --- a/src/ship/items/apply_item.rs +++ b/src/ship/items/apply_item.rs @@ -1,12 +1,14 @@ use std::convert::TryInto; use futures::future::join_all; use thiserror::Error; +use anyhow::Context; use rand::SeedableRng; use rand::distributions::{WeightedIndex, Distribution}; use crate::entity::gateway::{EntityGateway, GatewayError}; -use crate::entity::character::CharacterEntity; +use crate::entity::character::{CharacterEntity, TechLevel}; use crate::entity::item::mag::{MagCell, MagCellError}; use crate::entity::item::tool::{Tool, ToolType}; +use crate::entity::item::tech::{TechniqueDisk, Technique}; use crate::entity::item::{ItemDetail, ItemEntityId}; use crate::ship::items::state::{ItemStateProxy, ItemStateError}; use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail}; @@ -18,7 +20,7 @@ pub enum ApplyItemError { NoCharacter, #[error("item not equipped")] ItemNotEquipped, - #[error("invalid item")] + #[error("could not use item invalid item")] InvalidItem, #[error("gateway error {0}")] GatewayError(#[from] GatewayError), @@ -307,6 +309,21 @@ where } +async fn apply_tech<'a, EG>(item_state: &mut ItemStateProxy, + entity_gateway: &mut EG, + character: &mut CharacterEntity, + _entity_id: ItemEntityId, + tech: TechniqueDisk) + -> Result, anyhow::Error> +where + EG: EntityGateway + ?Sized, +{ + // TODO: make sure the class can learn that specific tech + character.techs.set_tech(tech.tech, TechLevel(tech.level as u8)); + entity_gateway.save_character(character).await.unwrap(); + Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) + +} pub async fn apply_item<'a, EG>(item_state: &mut ItemStateProxy, entity_gateway: &mut EG, @@ -320,7 +337,11 @@ where InventoryItemDetail::Individual(individual_item) => { match individual_item.item { ItemDetail::Tool(tool) => apply_tool(item_state, entity_gateway, character, individual_item.entity_id, tool.tool).await, - _ => Err(ApplyItemError::InvalidItem.into()) + ItemDetail::TechniqueDisk(tech) => apply_tech(item_state, entity_gateway, character, individual_item.entity_id, tech).await, + _ => Err(anyhow::Error::from(ApplyItemError::InvalidItem)) + .with_context(|| { + format!("item {:?}", individual_item) + }) } }, InventoryItemDetail::Stacked(stacked_item) => { diff --git a/tests/test_item_use.rs b/tests/test_item_use.rs index 2289822..f9a9b67 100644 --- a/tests/test_item_use.rs +++ b/tests/test_item_use.rs @@ -2,6 +2,7 @@ use elseware::common::serverstate::{ClientId, ServerState}; use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; use elseware::entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket}; +use elseware::entity::character::TechLevel; //use elseware::ship::items::{ClientItemId, ActiveItemEntityId, HeldItemType, FloorItemType}; use libpso::packet::ship::*; @@ -304,6 +305,92 @@ async fn test_jackolantern() { } } + +#[async_std::test] +async fn test_use_barta_1() { + let mut entity_gateway = InMemoryGateway::default(); + + let (user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; + + /* + let mut p1_inv = Vec::new(); + for tool in vec![item::tool::ToolType::PowerMaterial, item::tool::ToolType::].into_iter() { + let mut item = Vec::new(); + for _ in 0..5usize { + item.push(entity_gateway.create_item( + item::NewItemEntity { + item: item::ItemDetail::Tool( + item::tool::Tool { + tool: tool + } + ), + }).await.unwrap()); + } + p1_inv.push(item::InventoryItemEntity::Stacked(item)); +}*/ + let inv = vec![ + entity_gateway.create_item( + item::NewItemEntity { + item: item::ItemDetail::TechniqueDisk( + item::tech::TechniqueDisk { + tech: item::tech::Technique::Foie, + level: 3, + } + ) + } + ).await.unwrap(), + entity_gateway.create_item( + item::NewItemEntity { + item: item::ItemDetail::TechniqueDisk( + item::tech::TechniqueDisk { + tech: item::tech::Technique::Barta, + level: 4, + } + ) + } + ).await.unwrap(), + entity_gateway.create_item( + item::NewItemEntity { + item: item::ItemDetail::TechniqueDisk( + item::tech::TechniqueDisk { + tech: item::tech::Technique::Zonde, + level: 5, + } + ) + } + ).await.unwrap() + ]; + + entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(inv)).await.unwrap(); + + let mut ship = Box::new(ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build()); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + create_room(&mut ship, ClientId(1), "room", "").await; + + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { + client: 0, + target: 0, + item_id: 0x10000, + })))).await.unwrap(); + + ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { + client: 0, + target: 0, + item_id: 0x10002, + })))).await.unwrap(); + + let characters = entity_gateway.get_characters_by_user(&user1).await.unwrap(); + let char = characters[0].as_ref().unwrap(); + + assert_eq!(char.techs.techs.len(), 2); + assert_eq!(char.techs.techs.get(&item::tech::Technique::Foie).unwrap(), &TechLevel(3)); + assert_eq!(char.techs.techs.get(&item::tech::Technique::Zonde).unwrap(), &TechLevel(5)); + assert!(char.techs.techs.get(&item::tech::Technique::Barta).is_none()); +} + // TODO: tests for ALL ITEMS WOW /* -- 2.36.0 From 8157db4c69682f08d1c692a1c5c15f2f3a2460ae Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 23:56:28 -0700 Subject: [PATCH 21/30] set tech level correctly when reading from postgres --- src/entity/gateway/postgres/models.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entity/gateway/postgres/models.rs b/src/entity/gateway/postgres/models.rs index fd4980b..c310dda 100644 --- a/src/entity/gateway/postgres/models.rs +++ b/src/entity/gateway/postgres/models.rs @@ -244,7 +244,7 @@ impl From for CharacterEntity { prop_y: other.prop_y, }, techs: CharacterTechniques { - techs: other.techs.iter().enumerate().take(19).filter(|(_, t)| **t != 0xFF).map(|(i, t)| (tech::Technique::from_value(i as u8), TechLevel(*t)) ).collect() + techs: other.techs.iter().enumerate().take(19).filter(|(_, t)| **t != 0xFF).map(|(i, t)| (tech::Technique::from_value(i as u8), TechLevel(*t + 1)) ).collect() }, config: CharacterConfig { raw_data: vec_to_array(other.config) -- 2.36.0 From aa019d4ea976bc9850935061cd8be60299336a90 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 29 Jan 2023 23:57:17 -0700 Subject: [PATCH 22/30] pick the newest character for a slot when recreating --- .../migrations/V0010__char_create_timestamp.sql | 2 ++ src/entity/gateway/postgres/postgres.rs | 16 ++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 src/entity/gateway/postgres/migrations/V0010__char_create_timestamp.sql diff --git a/src/entity/gateway/postgres/migrations/V0010__char_create_timestamp.sql b/src/entity/gateway/postgres/migrations/V0010__char_create_timestamp.sql new file mode 100644 index 0000000..5ba1fd0 --- /dev/null +++ b/src/entity/gateway/postgres/migrations/V0010__char_create_timestamp.sql @@ -0,0 +1,2 @@ +alter table player_character + add created_at timestamptz default current_timestamp not null; diff --git a/src/entity/gateway/postgres/postgres.rs b/src/entity/gateway/postgres/postgres.rs index ba77827..0a81bb7 100644 --- a/src/entity/gateway/postgres/postgres.rs +++ b/src/entity/gateway/postgres/postgres.rs @@ -276,17 +276,17 @@ async fn create_character(conn: &mut sqlx::PgConnection, char: NewCharacterEntit async fn get_characters_by_user(conn: &mut sqlx::PgConnection, user: &UserAccountEntity) -> Result<[Option; 4], GatewayError> { - let mut stream = sqlx::query_as::<_, PgCharacter>("select * from player_character where user_account = $1 and slot < 4 order by slot") + let stream = sqlx::query_as::<_, PgCharacter>("select * from player_character where user_account = $1 and slot < 4 order by created_at;") .bind(user.id.0) .fetch(conn); - const NONE: Option = None; - let mut result = [NONE; 4]; - while let Some(character) = stream.try_next().await? { - let index = character.slot as usize; - result[index] = Some(character.into()) - } - Ok(result) + Ok(stream.fold(core::array::from_fn(|_| None), |mut acc, char| { + if let Ok(char) = char { + let slot = char.slot as usize; + acc[slot] = Some(char.into()) + } + acc + }).await) } async fn save_character(conn: &mut sqlx::PgConnection, char: &CharacterEntity) -> Result<(), GatewayError> -- 2.36.0 From 939c511f92133899b3c0b1a7da343413bded6907 Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 30 Jan 2023 10:43:12 -0700 Subject: [PATCH 23/30] add some atomizers --- src/ship/items/apply_item.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ship/items/apply_item.rs b/src/ship/items/apply_item.rs index c418645..5945350 100644 --- a/src/ship/items/apply_item.rs +++ b/src/ship/items/apply_item.rs @@ -275,6 +275,10 @@ where ToolType::Monofluid => Ok(Vec::new()), ToolType::Difluid => Ok(Vec::new()), ToolType::Trifluid => Ok(Vec::new()), + ToolType::SolAtomizer => Ok(Vec::new()), + ToolType::MoonAtomizer => Ok(Vec::new()), + ToolType::StarAtomizer => Ok(Vec::new()), + ToolType::Telepipe => Ok(Vec::new()), ToolType::HuntersReport => Ok(Vec::new()), ToolType::CellOfMag502 | ToolType::CellOfMag213 -- 2.36.0 From 7144ede73fefb4c89879e91486b41f031e2a393a Mon Sep 17 00:00:00 2001 From: andy Date: Mon, 30 Jan 2023 18:33:41 +0000 Subject: [PATCH 24/30] more green boxes --- src/ship/items/apply_item.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ship/items/apply_item.rs b/src/ship/items/apply_item.rs index 5945350..971b266 100644 --- a/src/ship/items/apply_item.rs +++ b/src/ship/items/apply_item.rs @@ -279,6 +279,9 @@ where ToolType::MoonAtomizer => Ok(Vec::new()), ToolType::StarAtomizer => Ok(Vec::new()), ToolType::Telepipe => Ok(Vec::new()), + ToolType::Antidote => Ok(Vec::new()), + ToolType::Antiparalysis => Ok(Vec::new()), + ToolType::TrapVision => Ok(Vec::new()), ToolType::HuntersReport => Ok(Vec::new()), ToolType::CellOfMag502 | ToolType::CellOfMag213 -- 2.36.0 From 1fb0abce093fb6b2d7c4e72c9c07726606b47deb Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 30 Jan 2023 10:46:42 -0700 Subject: [PATCH 25/30] more info on incorrect tool usage --- src/ship/items/apply_item.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ship/items/apply_item.rs b/src/ship/items/apply_item.rs index 971b266..5534b47 100644 --- a/src/ship/items/apply_item.rs +++ b/src/ship/items/apply_item.rs @@ -22,6 +22,8 @@ pub enum ApplyItemError { ItemNotEquipped, #[error("could not use item invalid item")] InvalidItem, + #[error("invalid tool")] + InvalidTool, #[error("gateway error {0}")] GatewayError(#[from] GatewayError), @@ -311,7 +313,11 @@ where } ToolType::JackOLantern => jack_o_lantern(), // TODO: rest of these - _ => Err(ApplyItemError::InvalidItem.into()) + _ => Err(anyhow::Error::from(ApplyItemError::InvalidTool)) + .with_context(|| { + format!("invalid tool {:?}", tool) + }) + } } -- 2.36.0 From 6ef5ea66816314061e3bd54e32730ce4e09fdb99 Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 30 Jan 2023 15:45:34 -0700 Subject: [PATCH 26/30] set mag owner when creating a char --- src/entity/item/mag.rs | 2 +- src/login/character.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/entity/item/mag.rs b/src/entity/item/mag.rs index dbdb4a7..17fa1b4 100644 --- a/src/entity/item/mag.rs +++ b/src/entity/item/mag.rs @@ -521,7 +521,7 @@ pub enum MagCellError { #[derive(Debug, Clone, PartialEq, Eq)] pub enum MagModifier { - FeedMag{ + FeedMag { food: ItemEntityId, }, BankMag, // when putting a mag in the bank it truncates the values which has applications when raising degenerate mags diff --git a/src/login/character.rs b/src/login/character.rs index cd6bb65..7f626cf 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -266,6 +266,8 @@ async fn new_character(entity_gateway: &mut EG, user: character_id: character.id, }).await?; + entity_gateway.change_mag_owner(&mag.id, &character).await?; + let mut monomates = Vec::new(); for _ in 0..4usize { let monomate = entity_gateway.create_item( -- 2.36.0 From f3682d0b8224fcb4d1552b7c3e75c2a5e3a3d3b2 Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 30 Jan 2023 18:05:36 -0700 Subject: [PATCH 27/30] clippy --- src/bin/main.rs | 2 +- src/entity/character.rs | 4 ++-- src/entity/gateway/entitygateway.rs | 1 - src/entity/gateway/postgres/postgres.rs | 4 ++-- src/lib.rs | 1 + src/login/character.rs | 2 +- src/patch/patch.rs | 6 +++--- src/ship/drops/mod.rs | 2 +- src/ship/items/apply_item.rs | 23 +++++------------------ src/ship/items/state.rs | 2 +- src/ship/map/enemy.rs | 2 +- src/ship/packet/handler/room.rs | 1 + src/ship/packet/handler/settings.rs | 2 +- src/ship/room.rs | 12 ++---------- src/ship/ship.rs | 13 ++----------- 15 files changed, 24 insertions(+), 53 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 2b262fc..9ff056b 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -52,7 +52,7 @@ fn main() { for i in 0..5 { let fake_user = NewUserAccountEntity { - email: format!("fake{}@email.com", i), + email: format!("fake{i}@email.com"), username: if i == 0 { "hi".to_string() } else { format!("hi{}", i+1) }, password: bcrypt::hash("qwer", 5).unwrap(), guildcard: i + 1, diff --git a/src/entity/character.rs b/src/entity/character.rs index ddf892a..080bb1b 100644 --- a/src/entity/character.rs +++ b/src/entity/character.rs @@ -2,8 +2,8 @@ use std::convert::{From, Into}; use std::collections::HashMap; use serde::{Serialize, Deserialize}; -use libpso::packet::ship::{UpdateConfig, WriteInfoboard, KeyboardConfig, GamepadConfig}; -use libpso::character::settings::{DEFAULT_PALETTE_CONFIG, DEFAULT_TECH_MENU, DEFAULT_KEYBOARD_CONFIG1, DEFAULT_KEYBOARD_CONFIG2, DEFAULT_KEYBOARD_CONFIG3, DEFAULT_KEYBOARD_CONFIG4, DEFAULT_GAMEPAD_CONFIG}; +use libpso::packet::ship::{UpdateConfig, WriteInfoboard}; +use libpso::character::settings::{DEFAULT_PALETTE_CONFIG, DEFAULT_TECH_MENU}; use crate::entity::item::tech::Technique; use crate::entity::account::UserAccountId; diff --git a/src/entity/gateway/entitygateway.rs b/src/entity/gateway/entitygateway.rs index c9cedc0..a8c47dc 100644 --- a/src/entity/gateway/entitygateway.rs +++ b/src/entity/gateway/entitygateway.rs @@ -1,4 +1,3 @@ -use std::convert::From; use thiserror::Error; use futures::Future; diff --git a/src/entity/gateway/postgres/postgres.rs b/src/entity/gateway/postgres/postgres.rs index 0a81bb7..dbc49d4 100644 --- a/src/entity/gateway/postgres/postgres.rs +++ b/src/entity/gateway/postgres/postgres.rs @@ -2,7 +2,7 @@ #![allow(clippy::explicit_auto_deref)] use std::convert::{From, TryFrom, Into}; -use futures::{Future, TryStreamExt}; +use futures::Future; use async_std::stream::StreamExt; use async_std::sync::{Arc, Mutex}; use libpso::character::guildcard; @@ -67,7 +67,7 @@ impl<'t> PostgresGateway<'t> { let pool = async_std::task::block_on(async move { PgPoolOptions::new() .max_connections(5) - .connect(&format!("postgresql://{}:{}@{}:5432/{}", username, password, host, dbname)).await.unwrap() + .connect(&format!("postgresql://{username}:{password}@{host}:5432/{dbname}")).await.unwrap() }); PostgresGateway { diff --git a/src/lib.rs b/src/lib.rs index 2c1ab47..2c3d9c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(clippy::type_complexity)] #![allow(incomplete_features)] #![feature(inline_const)] #![feature(drain_filter)] diff --git a/src/login/character.rs b/src/login/character.rs index 7f626cf..349d1dd 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -393,7 +393,7 @@ impl CharacterServerState { Ok(settings) => settings, Err(_) => { let user_settings = NewUserSettingsEntity::new(user.id); - self.entity_gateway.create_user_settings(user_settings).await.map_err(|err| CharacterError::CouldNotLoadSettings(err))? + self.entity_gateway.create_user_settings(user_settings).await.map_err(CharacterError::CouldNotLoadSettings)? } }; diff --git a/src/patch/patch.rs b/src/patch/patch.rs index 230c5bf..26441f8 100644 --- a/src/patch/patch.rs +++ b/src/patch/patch.rs @@ -395,18 +395,18 @@ pub struct PatchConfig { pub fn load_config() -> PatchConfig { let ini_file = match fs::File::open(std::path::Path::new("patch.ron")) { - Err(err) => panic!("Failed to open patch.ron config file. \n{}", err), + Err(err) => panic!("Failed to open patch.ron config file. \n{err}"), Ok(ini_file) => ini_file, }; let mut s = String::new(); if let Err(err) = (&ini_file).read_to_string(&mut s) { - panic!("Failed to read patch.ron config file. \n{}", err); + panic!("Failed to read patch.ron config file. \n{err}"); } let config: PatchConfig = match from_str(s.as_str()) { Ok(config) => config, - Err(err) => panic!("Failed to load values from patch.ron \n{}",err), + Err(err) => panic!("Failed to load values from patch.ron \n{err}"), }; config } diff --git a/src/ship/drops/mod.rs b/src/ship/drops/mod.rs index 9c20130..5d8062c 100644 --- a/src/ship/drops/mod.rs +++ b/src/ship/drops/mod.rs @@ -257,7 +257,7 @@ impl DropTableBuilder { unit_table: self.unit_table.unwrap_or_else(|| GenericUnitTable::new(episode, difficulty, section_id)), tool_table: self.tool_table.unwrap_or_else(|| ToolTable::new(episode, difficulty, section_id)), box_table: self.box_table.unwrap_or_else(|| BoxDropTable::new(episode, difficulty, section_id)), - rng: self.rng.unwrap_or_else(|| rand_chacha::ChaCha20Rng::from_entropy()), + rng: self.rng.unwrap_or_else(rand_chacha::ChaCha20Rng::from_entropy), } } } diff --git a/src/ship/items/apply_item.rs b/src/ship/items/apply_item.rs index 5534b47..9820226 100644 --- a/src/ship/items/apply_item.rs +++ b/src/ship/items/apply_item.rs @@ -8,9 +8,9 @@ use crate::entity::gateway::{EntityGateway, GatewayError}; use crate::entity::character::{CharacterEntity, TechLevel}; use crate::entity::item::mag::{MagCell, MagCellError}; use crate::entity::item::tool::{Tool, ToolType}; -use crate::entity::item::tech::{TechniqueDisk, Technique}; +use crate::entity::item::tech::TechniqueDisk; use crate::entity::item::{ItemDetail, ItemEntityId}; -use crate::ship::items::state::{ItemStateProxy, ItemStateError}; +use crate::ship::items::state::ItemStateProxy; use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail}; @@ -26,10 +26,6 @@ pub enum ApplyItemError { InvalidTool, #[error("gateway error {0}")] GatewayError(#[from] GatewayError), - - //#[error("itemstate error {0}")] - //ItemStateError(Box), - #[error("magcell error {0}")] MagCellError(#[from] MagCellError), } @@ -42,15 +38,6 @@ pub enum ApplyItemAction { //RemoveItem, } -/* -impl From for ApplyItemError { - fn from(other: ItemStateError) -> ApplyItemError { - ApplyItemError::ItemStateError(Box::new(other)) - } -} -*/ - - async fn power_material(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result, anyhow::Error> { character.materials.power += 1; entity_gateway.save_character(character).await?; @@ -315,14 +302,14 @@ where // TODO: rest of these _ => Err(anyhow::Error::from(ApplyItemError::InvalidTool)) .with_context(|| { - format!("invalid tool {:?}", tool) + format!("invalid tool {tool:?}") }) } } -async fn apply_tech<'a, EG>(item_state: &mut ItemStateProxy, +async fn apply_tech<'a, EG>(_item_state: &mut ItemStateProxy, entity_gateway: &mut EG, character: &mut CharacterEntity, _entity_id: ItemEntityId, @@ -353,7 +340,7 @@ where ItemDetail::TechniqueDisk(tech) => apply_tech(item_state, entity_gateway, character, individual_item.entity_id, tech).await, _ => Err(anyhow::Error::from(ApplyItemError::InvalidItem)) .with_context(|| { - format!("item {:?}", individual_item) + format!("item {individual_item:?}") }) } }, diff --git a/src/ship/items/state.rs b/src/ship/items/state.rs index 1267b1b..a166d8b 100644 --- a/src/ship/items/state.rs +++ b/src/ship/items/state.rs @@ -372,7 +372,7 @@ impl ItemState { .map(|item| (item.clone(), FloorType::Shared)) }) .ok_or_else(|| ItemStateError::NoFloorItem(*item_id)) - .with_context(|| format!("character {}\nlocal floors: {:#?}\nshared floors: {:#?}", character_id, local_floors, shared_floors)) + .with_context(|| format!("character {character_id}\nlocal floors: {local_floors:#?}\nshared floors: {shared_floors:#?}")) } } diff --git a/src/ship/map/enemy.rs b/src/ship/map/enemy.rs index 96e63cb..4989041 100644 --- a/src/ship/map/enemy.rs +++ b/src/ship/map/enemy.rs @@ -103,7 +103,7 @@ impl RareMonsterAppearTable { rand_chacha::ChaChaRng::from_entropy().gen::() < *self.appear_rate.get(monster).unwrap_or(&0.0f32) } - pub fn apply(&self, mut enemy: MapEnemy, event: ShipEvent) -> MapEnemy { + pub fn apply(&self, enemy: MapEnemy, event: ShipEvent) -> MapEnemy { if enemy.can_be_rare() && self.roll_is_rare(&enemy.monster) { enemy.into_rare(event) } diff --git a/src/ship/packet/handler/room.rs b/src/ship/packet/handler/room.rs index 0a108ca..4cdf611 100644 --- a/src/ship/packet/handler/room.rs +++ b/src/ship/packet/handler/room.rs @@ -16,6 +16,7 @@ use crate::ship::location::{ClientLocation, RoomId, RoomLobby, GetAreaError}; use crate::ship::packet::builder; use crate::ship::items::state::ItemState; +#[allow(clippy::too_many_arguments)] pub async fn create_room(id: ClientId, create_room: CreateRoom, client_location: &mut ClientLocation, diff --git a/src/ship/packet/handler/settings.rs b/src/ship/packet/handler/settings.rs index 3566b69..b40da3c 100644 --- a/src/ship/packet/handler/settings.rs +++ b/src/ship/packet/handler/settings.rs @@ -1,6 +1,6 @@ use libpso::packet::ship::*; use crate::common::serverstate::ClientId; -use crate::ship::ship::{SendShipPacket, ShipError, Clients}; +use crate::ship::ship::{SendShipPacket, Clients}; use crate::entity::gateway::EntityGateway; pub async fn update_config(id: ClientId, diff --git a/src/ship/room.rs b/src/ship/room.rs index a48bfc3..87e5585 100644 --- a/src/ship/room.rs +++ b/src/ship/room.rs @@ -13,12 +13,10 @@ use crate::ship::drops::DropTable; use crate::entity::character::SectionID; use crate::ship::monster::{load_monster_stats_table, MonsterType, MonsterStats}; use crate::ship::map::area::MapAreaLookup; -use crate::ship::map::enemy::RareMonsterAppearTable; use crate::ship::quests; use crate::ship::ship::{ShipError, ShipEvent}; use crate::ship::location::{MAX_ROOMS, RoomId}; - #[derive(Clone)] pub struct Rooms([Arc>>; MAX_ROOMS]); @@ -261,17 +259,11 @@ impl RoomMode { } pub fn battle(&self) -> bool { - match self { - RoomMode::Battle {..} => true, - _ => false, - } + matches!(self, RoomMode::Battle {..}) } pub fn challenge(&self) -> bool { - match self { - RoomMode::Challenge {..} => true, - _ => false, - } + matches!(self, RoomMode::Challenge {..}) } pub fn player_mode(&self) -> PlayerMode { diff --git a/src/ship/ship.rs b/src/ship/ship.rs index fc5581c..1d1bb47 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -2,11 +2,8 @@ use std::net::Ipv4Addr; use std::collections::HashMap; -use std::backtrace::Backtrace; - use async_std::channel; use async_std::sync::{Arc, Mutex, RwLock}; - use rand::Rng; use thiserror::Error; @@ -15,21 +12,15 @@ use libpso::packet::login::{RedirectClient, Login, LoginResponse, ShipList}; use libpso::packet::messages::*; use libpso::{PacketParseError, PSOPacket}; use libpso::crypto::bb::PSOBBCipher; - use libpso::packet::ship::{BLOCK_MENU_ID, ROOM_MENU_ID}; - use crate::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; use crate::common::interserver::{AuthToken, Ship, ServerId, InterserverActor, LoginMessage, ShipMessage}; - use crate::login::character::SHIP_MENU_ID; - use crate::entity::gateway::{EntityGateway, GatewayError}; use crate::entity::character::SectionID; - use crate::ship::location::{ClientLocation, RoomLobby, ClientLocationError, RoomId}; - use crate::ship::drops::DropTable; use crate::ship::items; use crate::ship::room; @@ -690,12 +681,12 @@ impl ServerState for ShipServerState { let block = self.blocks.get_from_client(id, &self.clients).await?; match menuselect.menu { 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().flatten(); let select_ship = handler::ship::selected_ship(id, menuselect, &self.ship_list).await?; leave_lobby.chain(select_ship).collect() } BLOCK_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().flatten(); let select_block = handler::lobby::block_selected(id, menuselect, &self.clients, &self.item_state).await?.into_iter(); leave_lobby.chain(select_block).collect() } -- 2.36.0 From 42ef2ebcbbcf45d4748a149bed436564d1b94326 Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 30 Jan 2023 18:12:43 -0700 Subject: [PATCH 28/30] clippy2 --- src/ship/items/actions.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ship/items/actions.rs b/src/ship/items/actions.rs index 2d41151..be6748b 100644 --- a/src/ship/items/actions.rs +++ b/src/ship/items/actions.rs @@ -6,8 +6,6 @@ use std::future::Future; use std::pin::Pin; use std::iter::IntoIterator; -use log::warn; - use libpso::packet::{ship::Message, messages::GameMessage}; use crate::ship::map::MapArea; use crate::ship::ship::SendShipPacket; @@ -885,7 +883,6 @@ where move |(mut item_state, mut transaction), _| { let item_drop = item_drop.clone(); Box::pin(async move { - warn!("converting item drop to floor item"); enum ItemOrMeseta { Individual(ItemDetail), Stacked(Tool), -- 2.36.0 From 8f6b562c2243a23259000e6a3d3c51d5bc021848 Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 30 Jan 2023 18:19:04 -0700 Subject: [PATCH 29/30] clippy3 --- src/ship/items/tasks.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ship/items/tasks.rs b/src/ship/items/tasks.rs index 984e341..ad3e585 100644 --- a/src/ship/items/tasks.rs +++ b/src/ship/items/tasks.rs @@ -17,8 +17,6 @@ use crate::ship::drops::ItemDrop; use crate::ship::items::actions; -use log::warn; - pub async fn pick_up_item( item_state: &mut ItemState, entity_gateway: &mut EG, -- 2.36.0 From 5b8f4fd087c0abd2a11477e3d535ddd23d6b69dc Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 30 Jan 2023 18:50:05 -0700 Subject: [PATCH 30/30] disconnect a client if any error occurs --- src/common/mainloop/client.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/common/mainloop/client.rs b/src/common/mainloop/client.rs index bca79d2..0ace697 100644 --- a/src/common/mainloop/client.rs +++ b/src/common/mainloop/client.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::fmt::Debug; +use std::io::Write; use async_std::channel; use async_std::io::prelude::{ReadExt, WriteExt}; use async_std::sync::{Arc, RwLock}; @@ -148,6 +149,26 @@ where }, Err(err) => { error!("[client recv {:?}] error {:?} ", client_id, err); + + let mut f = std::fs::File::options().create(true).append(true).open("errors.txt").unwrap(); + f.write_all(format!("[{client_id:?}] {err:?}").as_bytes()).unwrap(); + + // disconnect client on an error + for pkt in state.on_disconnect(client_id).await.unwrap() { + clients + .read() + .await + .get(&pkt.0) + .unwrap() + .send(pkt.1) + .await + .unwrap(); + } + clients + .write() + .await + .remove(&client_id); + break; } } } -- 2.36.0