diff --git a/src/entity/gateway/entitygateway.rs b/src/entity/gateway/entitygateway.rs index 2a8b65b..75518e1 100644 --- a/src/entity/gateway/entitygateway.rs +++ b/src/entity/gateway/entitygateway.rs @@ -19,15 +19,12 @@ pub enum GatewayError { #[async_trait::async_trait] pub trait EntityGateway: Send + Sync { - async fn transaction<'a>(&'a mut self) -> Result, GatewayError> - { - unimplemented!(); - } + type Transaction: EntityGatewayTransaction + Clone; async fn with_transaction<'a, F, Fut, R, E>(&'a mut self, _func: F) -> Result where - Fut: Future, R), E>> + Send + 'a, - F: FnOnce(Box) -> Fut + Send, + Fut: Future> + Send + 'a, + F: FnOnce(Self::Transaction) -> Fut + Send, R: Send, E: From, Self: Sized @@ -155,12 +152,14 @@ pub trait EntityGateway: Send + Sync { #[async_trait::async_trait] -pub trait EntityGatewayTransaction: Send + Sync { - fn gateway(&mut self) -> &mut dyn EntityGateway { +pub trait EntityGatewayTransaction: Send + Sync + Sized { + type ParentGateway: EntityGateway + Clone; + + fn gateway(&mut self) -> &mut Self::ParentGateway { unimplemented!() } - async fn commit(self: Box) -> Result<(), GatewayError> { + async fn commit(self) -> Result<(), GatewayError> { unimplemented!() } } diff --git a/src/entity/gateway/inmemory.rs b/src/entity/gateway/inmemory.rs index ba6f665..a813a93 100644 --- a/src/entity/gateway/inmemory.rs +++ b/src/entity/gateway/inmemory.rs @@ -9,10 +9,10 @@ use crate::entity::item::*; use async_std::sync::{Arc, Mutex}; -// TODO: implement multiple banks -pub struct InMemoryGatewayTransaction<'a> { +#[derive(Clone)] +pub struct InMemoryGatewayTransaction { working_gateway: InMemoryGateway, - original_gateway: &'a mut InMemoryGateway, + original_gateway: InMemoryGateway, } @@ -30,7 +30,9 @@ where // functions here have been skipped as they are not used in transactions, add as needed #[async_trait::async_trait] -impl<'a> EntityGateway for InMemoryGatewayTransaction<'a> { +impl EntityGateway for InMemoryGatewayTransaction { + type Transaction = InMemoryGatewayTransaction; + async fn create_user(&mut self, user: NewUserAccountEntity) -> Result { self.working_gateway.create_user(user).await } @@ -182,12 +184,14 @@ impl<'a> EntityGateway for InMemoryGatewayTransaction<'a> { } #[async_trait::async_trait] -impl<'a> EntityGatewayTransaction for InMemoryGatewayTransaction<'a> { - fn gateway(&mut self) -> &mut dyn EntityGateway { +impl EntityGatewayTransaction for InMemoryGatewayTransaction { + type ParentGateway = InMemoryGatewayTransaction; + + fn gateway(&mut self) -> &mut Self::ParentGateway { self } - async fn commit(mut self: Box) -> Result<(), GatewayError> { + async fn commit(mut self) -> Result<(), GatewayError> { self.original_gateway.users.lock().await.extend(self.working_gateway.users.lock().await.clone()); self.original_gateway.user_settings.lock().await.extend(self.working_gateway.user_settings.lock().await.clone()); self.original_gateway.characters.lock().await.extend(self.working_gateway.characters.lock().await.clone()); @@ -298,49 +302,12 @@ fn apply_modifiers(items: &BTreeMap, #[async_trait::async_trait] impl EntityGateway for InMemoryGateway { - async fn transaction<'a>(&'a mut self) -> Result, GatewayError> - { - let working_gateway = { - let users = self.users.lock().await.clone(); - let user_settings = self.user_settings.lock().await.clone(); - let characters = self.characters.lock().await.clone(); - let character_meseta = self.character_meseta.lock().await.clone(); - let bank_meseta = self.bank_meseta.lock().await.clone(); - let items = self.items.lock().await.clone(); - let inventories = self.inventories.lock().await.clone(); - let banks = self.banks.lock().await.clone(); - let equips = self.equips.lock().await.clone(); - let mag_modifiers = self.mag_modifiers.lock().await.clone(); - let weapon_modifiers = self.weapon_modifiers.lock().await.clone(); - let trades = self.trades.lock().await.clone(); - - InMemoryGateway { - users: Arc::new(Mutex::new(users)), - user_settings: Arc::new(Mutex::new(user_settings)), - characters: Arc::new(Mutex::new(characters)), - character_meseta: Arc::new(Mutex::new(character_meseta)), - bank_meseta: Arc::new(Mutex::new(bank_meseta)), - items: Arc::new(Mutex::new(items)), - inventories: Arc::new(Mutex::new(inventories)), - banks: Arc::new(Mutex::new(banks)), - equips: Arc::new(Mutex::new(equips)), - mag_modifiers: Arc::new(Mutex::new(mag_modifiers)), - weapon_modifiers: Arc::new(Mutex::new(weapon_modifiers)), - trades: Arc::new(Mutex::new(trades)), - } - }; - - Ok(Box::new(InMemoryGatewayTransaction { - working_gateway, - original_gateway: self, - })) - } - + type Transaction = InMemoryGatewayTransaction; async fn with_transaction<'a, F, Fut, R, E>(&'a mut self, func: F) -> Result where - Fut: Future, R), E>> + Send + 'a, - F: FnOnce(Box) -> Fut + Send, + Fut: Future> + Send + 'a, + F: FnOnce(Self::Transaction) -> Fut + Send, R: Send, E: From, { @@ -372,10 +339,10 @@ impl EntityGateway for InMemoryGateway { trades: Arc::new(Mutex::new(trades)), }; - let transaction = Box::new(InMemoryGatewayTransaction { + let transaction = InMemoryGatewayTransaction { working_gateway, - original_gateway: self, - }); + original_gateway: self.clone(), + }; let (transaction, result) = func(transaction).await?; diff --git a/src/entity/gateway/postgres/postgres.rs b/src/entity/gateway/postgres/postgres.rs index 813c810..d6ab8ee 100644 --- a/src/entity/gateway/postgres/postgres.rs +++ b/src/entity/gateway/postgres/postgres.rs @@ -4,6 +4,7 @@ use std::convert::{From, TryFrom, Into}; use futures::{Future, TryStreamExt}; use async_std::stream::StreamExt; +use async_std::sync::{Arc, Mutex}; use libpso::character::guildcard; use crate::entity::account::*; use crate::entity::character::*; @@ -21,31 +22,41 @@ mod embedded { } +#[derive(Clone)] pub struct PostgresTransaction<'t> { - pgtransaction: sqlx::Transaction<'t, sqlx::Postgres>, + pgtransaction: Arc>>, } #[async_trait::async_trait] impl<'t> EntityGatewayTransaction for PostgresTransaction<'t> { - fn gateway(&mut self) -> &mut dyn EntityGateway { + type ParentGateway = PostgresTransaction<'t>; + + fn gateway(&mut self) -> &mut Self::ParentGateway { self } - async fn commit(self: Box) -> Result<(), GatewayError> { - self.pgtransaction.commit().await?; + //async fn commit(self: Box) -> Result<(), GatewayError> { + async fn commit(self) -> Result<(), GatewayError> { + //self.pgtransaction.lock().await.commit().await?; + Arc::try_unwrap(self.pgtransaction) + .unwrap() + .into_inner() + .commit() + .await?; Ok(()) } } #[derive(Clone)] -pub struct PostgresGateway { +pub struct PostgresGateway<'t> { pool: sqlx::Pool, + _t: std::marker::PhantomData<&'t ()>, } -impl PostgresGateway { - pub fn new(host: &str, dbname: &str, username: &str, password: &str) -> PostgresGateway { +impl<'t> PostgresGateway<'t> { + pub fn new(host: &str, dbname: &str, username: &str, password: &str) -> PostgresGateway<'t> { let mut conn = refinery::config::Config::new(refinery::config::ConfigDbType::Postgres) .set_db_host(host) .set_db_user(username) @@ -61,6 +72,7 @@ impl PostgresGateway { PostgresGateway { pool, + _t: Default::default(), } } } @@ -581,24 +593,19 @@ async fn set_character_playtime(conn: &mut sqlx::PgConnection, char_id: &Charact } #[async_trait::async_trait] -impl EntityGateway for PostgresGateway { - async fn transaction<'a>(&'a mut self) -> Result, GatewayError> - { - Ok(Box::new(PostgresTransaction { - pgtransaction: self.pool.begin().await?, - })) - } +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 where - Fut: Future, R), E>> + Send + 'a, - F: FnOnce(Box) -> Fut + Send, + Fut: Future> + Send + 'a, + F: FnOnce(Self::Transaction) -> Fut + Send, R: Send, E: From, { - let transaction = Box::new(PostgresTransaction { - pgtransaction: self.pool.begin().await.map_err(|_| ()).unwrap() - }); + let transaction = PostgresTransaction { + pgtransaction: Arc::new(Mutex::new(self.pool.begin().await.map_err(|_| ()).unwrap())) + }; let (transaction, result) = func(transaction).await.map_err(|_| ()).unwrap(); transaction.commit().await.map_err(|_| ()).unwrap(); Ok(result) @@ -728,44 +735,46 @@ impl EntityGateway for PostgresGateway { #[async_trait::async_trait] impl<'c> EntityGateway for PostgresTransaction<'c> { + type Transaction = PostgresTransaction<'c>; + async fn create_user(&mut self, user: NewUserAccountEntity) -> Result { - create_user(&mut *self.pgtransaction, user).await + create_user(&mut *self.pgtransaction.lock().await, user).await } async fn get_user_by_id(&mut self, id: UserAccountId) -> Result { - get_user_by_id(&mut *self.pgtransaction, id).await + get_user_by_id(&mut *self.pgtransaction.lock().await, id).await } async fn get_user_by_name(&mut self, username: String) -> Result { - get_user_by_name(&mut *self.pgtransaction, username).await + get_user_by_name(&mut *self.pgtransaction.lock().await, username).await } async fn save_user(&mut self, user: &UserAccountEntity) -> Result<(), GatewayError> { - save_user(&mut *self.pgtransaction, user).await + save_user(&mut *self.pgtransaction.lock().await, user).await } async fn create_user_settings(&mut self, settings: NewUserSettingsEntity) -> Result { - create_user_settings(&mut *self.pgtransaction, settings).await + create_user_settings(&mut *self.pgtransaction.lock().await, settings).await } async fn get_user_settings_by_user(&mut self, user: &UserAccountEntity) -> Result { - get_user_settings_by_user(&mut *self.pgtransaction, user).await + get_user_settings_by_user(&mut *self.pgtransaction.lock().await, user).await } async fn save_user_settings(&mut self, settings: &UserSettingsEntity) -> Result<(), GatewayError> { - save_user_settings(&mut *self.pgtransaction, settings).await + save_user_settings(&mut *self.pgtransaction.lock().await, settings).await } async fn create_character(&mut self, char: NewCharacterEntity) -> Result { - create_character(&mut *self.pgtransaction, char).await + create_character(&mut *self.pgtransaction.lock().await, char).await } async fn get_characters_by_user(&mut self, user: &UserAccountEntity) -> Result<[Option; 4], GatewayError> { - get_characters_by_user(&mut *self.pgtransaction, user).await + get_characters_by_user(&mut *self.pgtransaction.lock().await, user).await } async fn save_character(&mut self, char: &CharacterEntity) -> Result<(), GatewayError> { - save_character(&mut *self.pgtransaction, char).await + save_character(&mut *self.pgtransaction.lock().await, char).await } async fn get_guild_card_data_by_user(&mut self, user: &UserAccountEntity) -> Result { @@ -777,75 +786,75 @@ impl<'c> EntityGateway for PostgresTransaction<'c> { } async fn create_item(&mut self, item: NewItemEntity) -> Result { - create_item(&mut *self.pgtransaction, item).await + create_item(&mut *self.pgtransaction.lock().await, item).await } async fn add_item_note(&mut self, item_id: &ItemEntityId, item_note: ItemNote) -> Result<(), GatewayError> { - add_item_note(&mut *self.pgtransaction, item_id, item_note).await + add_item_note(&mut *self.pgtransaction.lock().await, item_id, item_note).await } async fn feed_mag(&mut self, mag_item_id: &ItemEntityId, tool_item_id: &ItemEntityId) -> Result<(), GatewayError> { - feed_mag(&mut *self.pgtransaction, mag_item_id, tool_item_id).await + feed_mag(&mut *self.pgtransaction.lock().await, mag_item_id, tool_item_id).await } async fn change_mag_owner(&mut self, mag_item_id: &ItemEntityId, character: &CharacterEntity) -> Result<(), GatewayError> { - change_mag_owner(&mut *self.pgtransaction, mag_item_id, character).await + change_mag_owner(&mut *self.pgtransaction.lock().await, mag_item_id, character).await } async fn use_mag_cell(&mut self, mag_item_id: &ItemEntityId, mag_cell_id: &ItemEntityId) -> Result<(), GatewayError> { - use_mag_cell(&mut *self.pgtransaction, mag_item_id, mag_cell_id).await + use_mag_cell(&mut *self.pgtransaction.lock().await, mag_item_id, mag_cell_id).await } async fn add_weapon_modifier(&mut self, item_id: &ItemEntityId, modifier: weapon::WeaponModifier) -> Result<(), GatewayError> { - add_weapon_modifier(&mut *self.pgtransaction, item_id, modifier).await + add_weapon_modifier(&mut *self.pgtransaction.lock().await, item_id, modifier).await } async fn get_character_inventory(&mut self, char_id: &CharacterEntityId) -> Result { - get_character_inventory(&mut *self.pgtransaction, char_id).await + get_character_inventory(&mut *self.pgtransaction.lock().await, char_id).await } async fn get_character_bank(&mut self, char_id: &CharacterEntityId, bank_name: &BankName) -> Result { - get_character_bank(&mut *self.pgtransaction, char_id, bank_name).await + get_character_bank(&mut *self.pgtransaction.lock().await, char_id, bank_name).await } async fn set_character_inventory(&mut self, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError> { - set_character_inventory(&mut *self.pgtransaction, char_id, inventory).await + set_character_inventory(&mut *self.pgtransaction.lock().await, char_id, inventory).await } async fn set_character_bank(&mut self, char_id: &CharacterEntityId, bank: &BankEntity, bank_name: &BankName) -> Result<(), GatewayError> { - set_character_bank(&mut *self.pgtransaction, char_id, bank, bank_name).await + set_character_bank(&mut *self.pgtransaction.lock().await, char_id, bank, bank_name).await } async fn get_character_equips(&mut self, char_id: &CharacterEntityId) -> Result { - get_character_equips(&mut *self.pgtransaction, char_id).await + get_character_equips(&mut *self.pgtransaction.lock().await, char_id).await } async fn set_character_equips(&mut self, char_id: &CharacterEntityId, equips: &EquippedEntity) -> Result<(), GatewayError> { - set_character_equips(&mut *self.pgtransaction, char_id, equips).await + set_character_equips(&mut *self.pgtransaction.lock().await, char_id, equips).await } async fn set_character_meseta(&mut self, char_id: &CharacterEntityId, meseta: Meseta) -> Result<(), GatewayError> { - set_character_meseta(&mut *self.pgtransaction, char_id, meseta).await + set_character_meseta(&mut *self.pgtransaction.lock().await, char_id, meseta).await } async fn get_character_meseta(&mut self, char_id: &CharacterEntityId) -> Result { - get_character_meseta(&mut *self.pgtransaction, char_id).await + get_character_meseta(&mut *self.pgtransaction.lock().await, char_id).await } async fn set_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName, meseta: Meseta) -> Result<(), GatewayError> { - set_bank_meseta(&mut *self.pgtransaction, char_id, bank, meseta).await + set_bank_meseta(&mut *self.pgtransaction.lock().await, char_id, bank, meseta).await } async fn get_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName) -> Result { - get_bank_meseta(&mut *self.pgtransaction, char_id, bank).await + get_bank_meseta(&mut *self.pgtransaction.lock().await, char_id, bank).await } async fn create_trade(&mut self, char_id1: &CharacterEntityId, char_id2: &CharacterEntityId) -> Result { - create_trade(&mut *self.pgtransaction, char_id1, char_id2).await + create_trade(&mut *self.pgtransaction.lock().await, char_id1, char_id2).await } async fn set_character_playtime(&mut self, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError> { - set_character_playtime(&mut *self.pgtransaction, char_id, playtime).await + set_character_playtime(&mut *self.pgtransaction.lock().await, char_id, playtime).await } } diff --git a/src/login/character.rs b/src/login/character.rs index 87a3c4a..882ec03 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -21,7 +21,7 @@ use crate::common::interserver::{ServerId, InterserverActor, LoginMessage, ShipM use crate::common::leveltable::LEVEL_TABLE; use libpso::{utf8_to_array, utf8_to_utf16_array}; -use crate::entity::gateway::{EntityGateway, GatewayError}; +use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError}; use crate::entity::account::{UserAccountId, UserAccountEntity, NewUserSettingsEntity, USERFLAG_NEWCHAR, USERFLAG_DRESSINGROOM}; use crate::entity::item::{NewItemEntity, ItemDetail, ItemNote, InventoryItemEntity, InventoryEntity, BankEntity, BankName, EquippedEntity, Meseta}; use crate::entity::item::weapon::Weapon; @@ -830,6 +830,14 @@ mod test { use libpso::character::{settings, character}; use crate::entity::gateway::{InMemoryGateway, GatewayError}; + impl EntityGateway for () { + type Transaction = (); + } + + impl EntityGatewayTransaction for () { + type ParentGateway = (); + } + #[async_std::test] async fn test_option_send() { #[derive(Clone)] @@ -838,6 +846,7 @@ mod test { #[async_trait::async_trait] impl EntityGateway for TestData { + type Transaction = (); async fn get_user_settings_by_user(&mut self, user: &UserAccountEntity) -> Result { Ok(UserSettingsEntity { id: UserSettingsId(0), @@ -879,7 +888,9 @@ mod test { async fn test_user_checksum() { #[derive(Clone)] struct TestData; - impl EntityGateway for TestData {} + impl EntityGateway for TestData { + type Transaction = (); + } let mut server = CharacterServerState::new(TestData {}, AuthToken("".into())); let send = server.handle(ClientId(1), RecvCharacterPacket::Checksum(Checksum {checksum: 1234, padding: 0, diff --git a/src/login/login.rs b/src/login/login.rs index 5b2ce52..01ef4f1 100644 --- a/src/login/login.rs +++ b/src/login/login.rs @@ -14,7 +14,7 @@ use libpso::util::array_to_utf8; use crate::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; -use crate::entity::gateway::EntityGateway; +use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction}; use crate::entity::account::{UserAccountEntity}; pub const LOGIN_PORT: u16 = 12000; @@ -205,6 +205,14 @@ mod test { } }); + impl EntityGateway for () { + type Transaction = (); + } + + impl EntityGatewayTransaction for () { + type ParentGateway = (); + } + #[async_std::test] async fn test_correct_login() { #[derive(Clone)] @@ -213,6 +221,7 @@ mod test { #[async_trait::async_trait] impl EntityGateway for TestData { + type Transaction = (); async fn get_user_by_name(&mut self, name: String) -> Result { assert!(name == "testuser"); Ok(UserAccountEntity { @@ -271,6 +280,7 @@ mod test { #[async_trait::async_trait] impl EntityGateway for TestData { + type Transaction = (); async fn get_user_by_name(&mut self, _name: String) -> Result { Err(GatewayError::Error) } @@ -305,6 +315,7 @@ mod test { #[async_trait::async_trait] impl EntityGateway for TestData { + type Transaction = (); async fn get_user_by_name(&mut self, name: String) -> Result { assert!(name == "testuser"); Ok(UserAccountEntity { @@ -354,6 +365,7 @@ mod test { #[async_trait::async_trait] impl EntityGateway for TestData { + type Transaction = (); async fn get_user_by_name(&mut self, name: String) -> Result { assert!(name == "testuser"); Ok(UserAccountEntity { diff --git a/src/ship/items/actions.rs b/src/ship/items/actions.rs index e19c4ab..a5561bc 100644 --- a/src/ship/items/actions.rs +++ b/src/ship/items/actions.rs @@ -6,12 +6,12 @@ use std::pin::Pin; use crate::ship::map::MapArea; use crate::entity::character::{CharacterEntity, CharacterEntityId}; -use crate::entity::gateway::EntityGatewayTransaction; +use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction}; use crate::ship::items::state::{ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, IndividualItemDetail}; use crate::ship::items::bank::{BankItem, BankItemDetail}; use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail}; use crate::ship::items::floor::{FloorItem, FloorItemDetail}; -use crate::ship::items::apply_item::apply_item; +use crate::ship::items::apply_item::{apply_item, ApplyItemAction}; use crate::entity::item::{ItemDetail, NewItemEntity, TradeId}; use crate::entity::item::tool::Tool; use crate::entity::item::ItemModifier; @@ -23,11 +23,16 @@ pub enum TriggerCreateItem { No } -pub(super) fn take_item_from_floor(character_id: CharacterEntityId, item_id: ClientItemId) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) - -> Pin, Box), FloorItem), ItemStateError>> + Send + 'a>> +pub(super) fn take_item_from_floor( + character_id: CharacterEntityId, + item_id: ClientItemId +) -> impl Fn((ItemStateProxy, TR), ()) + -> Pin> + Send>> +where + EG: EntityGateway + Send, + TR: EntityGatewayTransaction + 'static, { - move |(mut item_state, transaction): (ItemStateProxy<'_>, Box) , _| { + move |(mut item_state, transaction): (ItemStateProxy, TR) , _| { Box::pin(async move { let mut floor = item_state.floor(&character_id).await?; let item = floor.take_item(&item_id).ok_or_else(|| ItemStateError::NoFloorItem(item_id))?; @@ -38,13 +43,18 @@ pub(super) fn take_item_from_floor(character_id: CharacterEntityId, item_id: Cli } } -pub(super) fn add_floor_item_to_inventory(character: &CharacterEntity) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), FloorItem) - -> Pin, Box), TriggerCreateItem), ItemStateError>> + Send + 'a>> +pub(super) fn add_floor_item_to_inventory( + character: &CharacterEntity +) -> impl Fn((ItemStateProxy, TR), FloorItem) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + Clone + 'static, { let character = character.clone(); move |(mut item_state, transaction), floor_item| { let character = character.clone(); + let transaction = transaction.clone(); Box::pin(async move { let mut inventory = item_state.inventory(&character.id).await?; @@ -67,7 +77,7 @@ pub(super) fn add_floor_item_to_inventory(character: &CharacterEntity) let add_result = inventory.add_floor_item(floor_item)?; transaction.gateway().set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?; - item_state.set_inventory(inventory); + item_state.set_inventory(inventory).await; Ok(((item_state, transaction), match add_result { @@ -81,9 +91,15 @@ pub(super) fn add_floor_item_to_inventory(character: &CharacterEntity) -pub(super) fn take_item_from_inventory(character_id: CharacterEntityId, item_id: ClientItemId, amount: u32) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) - -> Pin, Box), InventoryItem), ItemStateError>> + Send + 'a>> +pub(super) fn take_item_from_inventory( + character_id: CharacterEntityId, + item_id: ClientItemId, + amount: u32, +) -> impl Fn((ItemStateProxy, TR), ()) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, mut transaction), _| { Box::pin(async move { @@ -91,7 +107,7 @@ pub(super) fn take_item_from_inventory(character_id: CharacterEntityId, item_id: let item = inventory.take_item(&item_id, amount).ok_or_else(|| ItemStateError::NoFloorItem(item_id))?; transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?; - item_state.set_inventory(inventory); + item_state.set_inventory(inventory).await; Ok(((item_state, transaction), item)) }) @@ -99,9 +115,15 @@ pub(super) fn take_item_from_inventory(character_id: CharacterEntityId, item_id: } -pub(super) fn add_inventory_item_to_shared_floor(character_id: CharacterEntityId, map_area: MapArea, drop_position: (f32, f32, f32)) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), InventoryItem) - -> Pin, Box), FloorItem), ItemStateError>> + Send + 'a>> +pub(super) fn add_inventory_item_to_shared_floor( + character_id: CharacterEntityId, + map_area: MapArea, + drop_position: (f32, f32, f32), +) -> impl Fn((ItemStateProxy, TR), InventoryItem) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, transaction), inventory_item| { Box::pin(async move { @@ -127,43 +149,59 @@ pub(super) fn add_inventory_item_to_shared_floor(character_id: CharacterEntityId } -pub(super) fn take_meseta_from_inventory(character_id: CharacterEntityId, amount: u32) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) - -> Pin, Box), ()), ItemStateError>> + Send + 'a>> +pub(super) fn take_meseta_from_inventory( + character_id: CharacterEntityId, + amount: u32, +) -> impl Fn((ItemStateProxy, TR), ()) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, mut transaction), _| { Box::pin(async move { let mut inventory = item_state.inventory(&character_id).await?; inventory.remove_meseta(amount)?; transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?; - item_state.set_inventory(inventory); + item_state.set_inventory(inventory).await; Ok(((item_state, transaction), ())) }) } } -pub(super) fn add_meseta_to_inventory(character_id: CharacterEntityId, amount: u32) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) - -> Pin, Box), ()), ItemStateError>> + Send + 'a>> +pub(super) fn add_meseta_to_inventory( + character_id: CharacterEntityId, + amount: u32 +) -> impl Fn((ItemStateProxy, TR), ()) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, mut transaction), _| { Box::pin(async move { let mut inventory = item_state.inventory(&character_id).await?; inventory.add_meseta(amount)?; transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?; - item_state.set_inventory(inventory); + item_state.set_inventory(inventory).await; Ok(((item_state, transaction), ())) }) } } -pub(super) fn add_meseta_to_shared_floor(character_id: CharacterEntityId, amount: u32, map_area: MapArea, drop_position: (f32, f32)) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) - -> Pin, Box), FloorItem), ItemStateError>> + Send + 'a>> +pub(super) fn add_meseta_to_shared_floor( + character_id: CharacterEntityId, + amount: u32, + map_area: MapArea, + drop_position: (f32, f32) +) -> impl Fn((ItemStateProxy, TR), ()) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { - move |(mut item_state, transaction), _| { Box::pin(async move { let floor_item = FloorItem { @@ -184,9 +222,14 @@ pub(super) fn add_meseta_to_shared_floor(character_id: CharacterEntityId, amount } } -pub(super) fn take_meseta_from_bank(character_id: CharacterEntityId, amount: u32) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) - -> Pin, Box), ()), ItemStateError>> + Send + 'a>> +pub(super) fn take_meseta_from_bank( + character_id: CharacterEntityId, + amount: u32, +) -> impl Fn((ItemStateProxy, TR), ()) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, mut transaction), _| { Box::pin(async move { @@ -199,9 +242,14 @@ pub(super) fn take_meseta_from_bank(character_id: CharacterEntityId, amount: u32 } } -pub(super) fn add_meseta_from_bank_to_inventory(character_id: CharacterEntityId, amount: u32) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) - -> Pin, Box), ()), ItemStateError>> + Send + 'a>> +pub(super) fn add_meseta_from_bank_to_inventory( + character_id: CharacterEntityId, + amount: u32, +) -> impl Fn((ItemStateProxy, TR), ()) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, mut transaction), _| { Box::pin(async move { @@ -215,9 +263,14 @@ pub(super) fn add_meseta_from_bank_to_inventory(character_id: CharacterEntityId, } -pub(super) fn add_meseta_to_bank(character_id: CharacterEntityId, amount: u32) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) - -> Pin, Box), ()), ItemStateError>> + Send + 'a>> +pub(super) fn add_meseta_to_bank( + character_id: CharacterEntityId, + amount: u32, +) -> impl Fn((ItemStateProxy, TR), ()) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, mut transaction), _| { Box::pin(async move { @@ -231,25 +284,35 @@ pub(super) fn add_meseta_to_bank(character_id: CharacterEntityId, amount: u32) } -pub(super) fn take_item_from_bank(character_id: CharacterEntityId, item_id: ClientItemId, amount: u32) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) - -> Pin, Box), BankItem), ItemStateError>> + Send + 'a>> +pub(super) fn take_item_from_bank( + character_id: CharacterEntityId, + item_id: ClientItemId, + amount: u32, +) -> impl Fn((ItemStateProxy, TR), ()) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, mut transaction), _| { Box::pin(async move { let mut bank = item_state.bank(&character_id).await?; let item = bank.take_item(&item_id, amount).ok_or_else(|| ItemStateError::NoBankItem(item_id))?; transaction.gateway().set_character_bank(&character_id, &bank.as_bank_entity(), &bank.name).await?; - item_state.set_bank(bank); + item_state.set_bank(bank).await; Ok(((item_state, transaction), item)) }) } } -pub(super) fn add_bank_item_to_inventory(character: &CharacterEntity) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), BankItem) - -> Pin, Box), InventoryItem), ItemStateError>> + Send + 'a>> +pub(super) fn add_bank_item_to_inventory( + character: &CharacterEntity, +) -> impl Fn((ItemStateProxy, TR), BankItem) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { let character = character.clone(); move |(mut item_state, transaction), bank_item| { @@ -286,7 +349,7 @@ pub(super) fn add_bank_item_to_inventory(character: &CharacterEntity) inventory.add_item(inventory_item.clone())?; transaction.gateway().set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - item_state.set_inventory(inventory); + item_state.set_inventory(inventory).await; Ok(((item_state, transaction), inventory_item)) }) @@ -294,9 +357,13 @@ pub(super) fn add_bank_item_to_inventory(character: &CharacterEntity) } -pub(super) fn add_inventory_item_to_bank(character_id: CharacterEntityId) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), InventoryItem) - -> Pin, Box), ()), ItemStateError>> + Send + 'a>> +pub(super) fn add_inventory_item_to_bank( + character_id: CharacterEntityId, +) -> impl Fn((ItemStateProxy, TR), InventoryItem) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, transaction), inventory_item| { Box::pin(async move { @@ -315,7 +382,7 @@ pub(super) fn add_inventory_item_to_bank(character_id: CharacterEntityId) bank.add_inventory_item(inventory_item)?; transaction.gateway().set_character_bank(&character_id, &bank.as_bank_entity(), &bank.name).await?; - item_state.set_bank(bank); + item_state.set_bank(bank).await; Ok(((item_state, transaction), ())) @@ -324,16 +391,22 @@ pub(super) fn add_inventory_item_to_bank(character_id: CharacterEntityId) } -pub(super) fn equip_inventory_item(character_id: CharacterEntityId, item_id: ClientItemId, equip_slot: u8) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) - -> Pin, Box), ()), ItemStateError>> + Send + 'a>> +pub(super) fn equip_inventory_item( + character_id: CharacterEntityId, + item_id: ClientItemId, + equip_slot: u8, +) -> impl Fn((ItemStateProxy, TR), ()) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, mut transaction), _| { Box::pin(async move { let mut inventory = item_state.inventory(&character_id).await?; inventory.equip(&item_id, equip_slot); transaction.gateway().set_character_equips(&character_id, &inventory.as_equipped_entity()).await?; - item_state.set_inventory(inventory); + item_state.set_inventory(inventory).await; Ok(((item_state, transaction), ())) }) @@ -341,16 +414,21 @@ pub(super) fn equip_inventory_item(character_id: CharacterEntityId, item_id: Cli } -pub(super) fn unequip_inventory_item(character_id: CharacterEntityId, item_id: ClientItemId) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) - -> Pin, Box), ()), ItemStateError>> + Send + 'a>> +pub(super) fn unequip_inventory_item( + character_id: CharacterEntityId, + item_id: ClientItemId, +) -> impl Fn((ItemStateProxy, TR), ()) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, mut transaction), _| { Box::pin(async move { let mut inventory = item_state.inventory(&character_id).await?; inventory.unequip(&item_id); transaction.gateway().set_character_equips(&character_id, &inventory.as_equipped_entity()).await?; - item_state.set_inventory(inventory); + item_state.set_inventory(inventory).await; Ok(((item_state, transaction), ())) }) @@ -359,9 +437,14 @@ pub(super) fn unequip_inventory_item(character_id: CharacterEntityId, item_id: C -pub(super) fn sort_inventory_items(character_id: CharacterEntityId, item_ids: Vec) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) - -> Pin, Box), ()), ItemStateError>> + Send + 'a>> +pub(super) fn sort_inventory_items( + character_id: CharacterEntityId, + item_ids: Vec, +) -> impl Fn((ItemStateProxy, TR), ()) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, mut transaction), _| { let item_ids = item_ids.clone(); @@ -369,7 +452,7 @@ pub(super) fn sort_inventory_items(character_id: CharacterEntityId, item_ids: Ve let mut inventory = item_state.inventory(&character_id).await?; inventory.sort(&item_ids); transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?; - item_state.set_inventory(inventory); + item_state.set_inventory(inventory).await; Ok(((item_state, transaction), ())) }) @@ -377,9 +460,13 @@ pub(super) fn sort_inventory_items(character_id: CharacterEntityId, item_ids: Ve } -pub(super) fn use_consumed_item(character: CharacterEntity) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), InventoryItem) - -> Pin, Box), CharacterEntity), ItemStateError>> + Send + 'a>> +pub(super) fn use_consumed_item( + character: CharacterEntity, +) -> impl Fn((ItemStateProxy, TR), InventoryItem) + -> Pin), ItemStateError>> + Send>> +where + EG: EntityGateway + Clone + 'static, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, transaction), inventory_item| { let mut character = character.clone(); @@ -390,17 +477,22 @@ pub(super) fn use_consumed_item(character: CharacterEntity) Ok(transaction) }}).await?; - apply_item(&mut item_state, transaction.gateway(), &mut character, inventory_item).await?; + let apply_item_actions = apply_item(&mut item_state, transaction.gateway(), &mut character, inventory_item).await?; - Ok(((item_state, transaction), character)) + Ok(((item_state, transaction), apply_item_actions)) }) } } -pub(super) fn feed_mag_item(character: CharacterEntity, mag_item_id: ClientItemId) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), InventoryItem) - -> Pin, Box), CharacterEntity), ItemStateError>> + Send + 'a>> +pub(super) fn feed_mag_item( + character: CharacterEntity, + mag_item_id: ClientItemId, +) -> impl Fn((ItemStateProxy, TR), InventoryItem) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, transaction), tool| { let character = character.clone(); @@ -437,7 +529,7 @@ pub(super) fn feed_mag_item(character: CharacterEntity, mag_item_id: ClientItemI mag_entity.feed(food_tool); transaction.gateway().set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - item_state.set_inventory(inventory); + item_state.set_inventory(inventory).await; Ok(((item_state, transaction), character)) }) @@ -445,12 +537,16 @@ pub(super) fn feed_mag_item(character: CharacterEntity, mag_item_id: ClientItemI } -pub(super) fn add_bought_item_to_inventory<'a>(character_id: CharacterEntityId, - shop_item: &'a (dyn ShopItem + Send + Sync), - item_id: ClientItemId, - amount: u32) - -> impl Fn((ItemStateProxy<'a>, Box), ()) - -> Pin, Box), InventoryItem), ItemStateError>> + Send + 'a>> +pub(super) fn add_bought_item_to_inventory<'a, EG, TR>( + character_id: CharacterEntityId, + shop_item: &'a (dyn ShopItem + Send + Sync), + item_id: ClientItemId, + amount: u32, +) -> impl Fn((ItemStateProxy, TR), ()) + -> Pin> + Send + 'a>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, mut transaction), _| { Box::pin(async move { @@ -499,16 +595,20 @@ pub(super) fn add_bought_item_to_inventory<'a>(character_id: CharacterEntityId, }; transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?; - item_state.set_inventory(inventory); + item_state.set_inventory(inventory).await; Ok(((item_state, transaction), inventory_item)) }) } } -pub(super) fn sell_inventory_item<'a>(character_id: CharacterEntityId) - -> impl Fn((ItemStateProxy<'a>, Box), InventoryItem) - -> Pin, Box), InventoryItem), ItemStateError>> + Send + 'a>> +pub(super) fn sell_inventory_item( + character_id: CharacterEntityId, +) -> impl Fn((ItemStateProxy, TR), InventoryItem) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, transaction), inventory_item| { Box::pin(async move { @@ -522,7 +622,7 @@ pub(super) fn sell_inventory_item<'a>(character_id: CharacterEntityId) Ok(transaction) }}).await?; transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?; - item_state.set_inventory(inventory); + item_state.set_inventory(inventory).await; Ok(((item_state, transaction), inventory_item)) }) } @@ -530,19 +630,22 @@ pub(super) fn sell_inventory_item<'a>(character_id: CharacterEntityId) #[async_recursion::async_recursion] -async fn iterate_inner<'a, I, O, T, F, FR>(state: (ItemStateProxy<'a>, Box), - mut input: Vec, - func: F, - arg: T) - -> Result<((ItemStateProxy<'a>, Box), Vec), ItemStateError> +async fn iterate_inner<'a, EG, TR, I, O, T, F, FR>( + state: (ItemStateProxy, TR), + mut input: Vec, + func: F, + arg: T, +) -> Result<((ItemStateProxy, TR), Vec), ItemStateError> where 'a: 'async_recursion, + EG: EntityGateway, + TR: EntityGatewayTransaction, I: Send, O: Send, T: Clone + Send + Sync, F: Fn(I) -> FR + Send + Sync + Clone + 'static, - FR: Fn((ItemStateProxy<'a>, Box), T) - -> Pin, Box), O), ItemStateError>> + Send + 'a>> + Send + Sync, + FR: Fn((ItemStateProxy, TR), T) + -> Pin> + Send>> + Send + Sync, { let item = match input.pop() { Some(item) => item, @@ -558,18 +661,20 @@ where Ok((state, output)) } -pub(super) fn iterate<'k, I, O, T, F, FR>( +pub(super) fn iterate<'k, EG, TR, I, O, T, F, FR>( input: Vec, - func: F) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), T) - -> Pin, Box), Vec), ItemStateError>> + Send + 'a>> + func: F, +) -> impl Fn((ItemStateProxy, TR), T) + -> Pin), ItemStateError>> + Send>> where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, O: Send, I: Send + Clone + 'static + std::fmt::Debug, T: Send + Clone + 'static + std::fmt::Debug, F: Fn(I) -> FR + Send + Sync + Clone + 'static, - FR: for<'a> Fn((ItemStateProxy<'a>, Box), T) - -> Pin, Box), O), ItemStateError>> + Send + 'a>> + Send + Sync, + FR: Fn((ItemStateProxy, TR), T) + -> Pin> + Send>> + Send + Sync, T: Clone + Send + Sync, { move |(item_state, transaction), arg| { @@ -584,16 +689,19 @@ where #[async_recursion::async_recursion] -async fn foreach_inner<'a, O, T, F>(state: (ItemStateProxy<'a>, Box), - mut input: Vec, - func: F) - -> Result<((ItemStateProxy<'a>, Box), Vec), ItemStateError> +async fn foreach_inner<'a, EG, TR, O, T, F>( + state: (ItemStateProxy, TR), + mut input: Vec, + func: F, +) -> Result<((ItemStateProxy, TR), Vec), ItemStateError> where 'a: 'async_recursion, + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, O: Send, T: Clone + Send, - F: Fn((ItemStateProxy<'a>, Box), T) - -> Pin, Box), O), ItemStateError>> + Send + 'a>> + Send + Sync, + F: Fn((ItemStateProxy, TR), T) + -> Pin> + Send>> + Send + Sync, F: Clone, { let item = match input.pop() { @@ -609,14 +717,17 @@ where Ok((state, output)) } -pub(super) fn foreach<'k, O, T, F>(func: F) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), Vec) - -> Pin, Box), Vec), ItemStateError>> + Send + 'a>> +pub(super) fn foreach<'k, EG, TR, O, T, F>( + func: F +) -> impl Fn((ItemStateProxy, TR), Vec) + -> Pin), ItemStateError>> + Send>> where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, O: Send, T: Send + Clone + 'static + std::fmt::Debug, - F: for<'a> Fn((ItemStateProxy<'a>, Box), T) - -> Pin, Box), O), ItemStateError>> + Send + 'a>> + Send + Sync + 'static, + F: Fn((ItemStateProxy, TR), T) + -> Pin> + Send>> + Send + Sync + 'static, F: Clone, T: Clone + Send + Sync, { @@ -629,9 +740,14 @@ where } } -pub(super) fn insert<'a, T: Send + Clone + 'a>(element: T) - -> impl Fn((ItemStateProxy<'a>, Box), ()) - -> Pin, Box), T), ItemStateError>> + Send + 'a>> +pub(super) fn insert<'a, EG, TR, T>( + element: T +) -> impl Fn((ItemStateProxy, TR), ()) + -> Pin> + Send + 'a>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, + T: Send + Clone + 'a, { move |state, _| { let element = element.clone(); @@ -641,9 +757,13 @@ pub(super) fn insert<'a, T: Send + Clone + 'a>(element: T) } } -pub(super) fn add_item_to_inventory(character: CharacterEntity) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), InventoryItem) - -> Pin, Box), InventoryItem), ItemStateError>> + Send + 'a>> + Clone +pub(super) fn add_item_to_inventory( + character: CharacterEntity, +) -> impl Fn((ItemStateProxy, TR), InventoryItem) + -> Pin> + Send>> + Clone +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, transaction), inventory_item| { let character = character.clone(); @@ -658,16 +778,22 @@ pub(super) fn add_item_to_inventory(character: CharacterEntity) inventory.add_item(inventory_item.clone())?; transaction.gateway().set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - item_state.set_inventory(inventory); + item_state.set_inventory(inventory).await; Ok(((item_state, transaction), inventory_item)) }) } } -pub(super) fn record_trade(trade_id: TradeId, character_to: CharacterEntityId, character_from: CharacterEntityId) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), Vec) - -> Pin, Box), Vec), ItemStateError>> + Send + 'a>> + Clone +pub(super) fn record_trade( + trade_id: TradeId, + character_to: CharacterEntityId, + character_from: CharacterEntityId, +) -> impl Fn((ItemStateProxy, TR), Vec) + -> Pin), ItemStateError>> + Send>> + Clone +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(item_state, mut transaction), traded_items| { Box::pin(async move { @@ -688,9 +814,12 @@ pub(super) fn record_trade(trade_id: TradeId, character_to: CharacterEntityId, c } -pub(super) fn assign_new_item_id() - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), InventoryItem) - -> Pin, Box), InventoryItem), ItemStateError>> + Send + 'a>> + Clone +pub(super) fn assign_new_item_id( +) -> impl Fn((ItemStateProxy, TR), InventoryItem) + -> Pin> + Send>> + Clone +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, transaction), mut inventory_item| { Box::pin(async move { @@ -701,9 +830,14 @@ pub(super) fn assign_new_item_id() } -pub(super) fn convert_item_drop_to_floor_item(character_id: CharacterEntityId, item_drop: ItemDrop) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) - -> Pin, Box), FloorItem), ItemStateError>> + Send + 'a>> + Clone +pub(super) fn convert_item_drop_to_floor_item( + character_id: CharacterEntityId, + item_drop: ItemDrop, +) -> impl Fn((ItemStateProxy, TR), ()) + -> Pin> + Send>> + Clone +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, mut transaction), _| { let item_drop = item_drop.clone(); @@ -798,9 +932,13 @@ pub(super) fn convert_item_drop_to_floor_item(character_id: CharacterEntityId, i } } -pub(super) fn add_item_to_local_floor(character_id: CharacterEntityId) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), FloorItem) - -> Pin, Box), FloorItem), ItemStateError>> + Send + 'a>> +pub(super) fn add_item_to_local_floor( + character_id: CharacterEntityId, +) -> impl Fn((ItemStateProxy, TR), FloorItem) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(mut item_state, transaction) , floor_item| { Box::pin(async move { @@ -813,9 +951,13 @@ pub(super) fn add_item_to_local_floor(character_id: CharacterEntityId) } } -pub(super) fn apply_modifier_to_inventory_item(modifier: ItemModifier) - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), InventoryItem) - -> Pin, Box), InventoryItem), ItemStateError>> + Send + 'a>> +pub(super) fn apply_modifier_to_inventory_item( + modifier: ItemModifier, +) -> impl Fn((ItemStateProxy, TR), InventoryItem) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(item_state, mut transaction), mut inventory_item| { let modifier = modifier.clone(); @@ -833,9 +975,12 @@ pub(super) fn apply_modifier_to_inventory_item(modifier: ItemModifier) } } -pub(super) fn as_individual_item() - -> impl for<'a> Fn((ItemStateProxy<'a>, Box), InventoryItem) - -> Pin, Box), IndividualItemDetail), ItemStateError>> + Send + 'a>> +pub(super) fn as_individual_item( +) -> impl Fn((ItemStateProxy, TR), InventoryItem) + -> Pin> + Send>> +where + EG: EntityGateway, + TR: EntityGatewayTransaction + 'static, { move |(item_state, transaction), inventory_item| { Box::pin(async move { diff --git a/src/ship/items/apply_item.rs b/src/ship/items/apply_item.rs index 598678f..7508358 100644 --- a/src/ship/items/apply_item.rs +++ b/src/ship/items/apply_item.rs @@ -1,5 +1,7 @@ -use thiserror::Error; use std::convert::TryInto; +use futures::future::{join_all, BoxFuture, LocalBoxFuture}; +use futures::stream::{FuturesOrdered, StreamExt}; +use thiserror::Error; use crate::entity::gateway::{EntityGateway, GatewayError}; use crate::entity::character::CharacterEntity; use crate::entity::item::mag::{MagCell, MagCellError}; @@ -27,53 +29,57 @@ pub enum ApplyItemError { MagCellError(#[from] MagCellError), } +pub enum ApplyItemAction { + UpdateCharacter(CharacterEntity), + CreateItem(()), +} + impl From for ApplyItemError { fn from(other: ItemStateError) -> ApplyItemError { ApplyItemError::ItemStateError(Box::new(other)) } } -// TODO: make all these functions not-pub -pub 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, ApplyItemError> { character.materials.power += 1; entity_gateway.save_character(character).await?; - Ok(()) + Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())]) } -pub 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, ApplyItemError> { character.materials.mind += 1; entity_gateway.save_character(character).await.unwrap(); - Ok(()) + Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())]) } -pub 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, ApplyItemError> { character.materials.evade += 1; entity_gateway.save_character(character).await.unwrap(); - Ok(()) + Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())]) } -pub 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, ApplyItemError> { character.materials.def += 1; entity_gateway.save_character(character).await.unwrap(); - Ok(()) + Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())]) } -pub 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, ApplyItemError> { character.materials.luck += 1; entity_gateway.save_character(character).await.unwrap(); - Ok(()) + Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())]) } -pub 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, ApplyItemError> { character.materials.hp += 1; entity_gateway.save_character(character).await.unwrap(); - Ok(()) + Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())]) } -pub 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, ApplyItemError> { character.materials.tp += 1; entity_gateway.save_character(character).await.unwrap(); - Ok(()) + Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())]) } /* @@ -98,12 +104,12 @@ async fn mag_cell(entity_gateway: &mut EG, used_cell: &Consum */ -async fn mag_cell<'a, EG>(item_state: &mut ItemStateProxy<'a>, +async fn mag_cell<'a, EG>(item_state: &mut ItemStateProxy, entity_gateway: &mut EG, character: &CharacterEntity, cell_entity_id: ItemEntityId, mag_cell_type: MagCell) - -> Result<(), ApplyItemError> + -> Result, ApplyItemError> where EG: EntityGateway + ?Sized, { @@ -117,7 +123,7 @@ where entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; item_state.set_inventory(inventory); - Ok(()) + Ok(Vec::new()) } /* @@ -218,12 +224,21 @@ pub async fn liberta_kit(entity_gateway: &mut EG, used_cell: } */ -async fn apply_tool<'a, EG>(item_state: &mut ItemStateProxy<'a>, +async fn jack_o_lantern<'a, EG>(item_state: &mut ItemStateProxy, + entity_gateway: &mut EG +) -> Result, ApplyItemError> +where + EG: EntityGateway + ?Sized, +{ + Ok(Vec::new()) +} + +async fn apply_tool<'a, EG>(item_state: &mut ItemStateProxy, entity_gateway: &mut EG, character: &mut CharacterEntity, entity_id: ItemEntityId, tool: ToolType) - -> Result<(), ApplyItemError> + -> Result, ApplyItemError> where EG: EntityGateway + ?Sized, { @@ -235,13 +250,13 @@ where ToolType::LuckMaterial => luck_material(entity_gateway, character).await, ToolType::HpMaterial => hp_material(entity_gateway, character).await, ToolType::TpMaterial => tp_material(entity_gateway, character).await, - ToolType::Monomate => Ok(()), - ToolType::Dimate => Ok(()), - ToolType::Trimate => Ok(()), - ToolType::Monofluid => Ok(()), - ToolType::Difluid => Ok(()), - ToolType::Trifluid => Ok(()), - ToolType::HuntersReport => Ok(()), + ToolType::Monomate => Ok(Vec::new()), + ToolType::Dimate => Ok(Vec::new()), + ToolType::Trimate => Ok(Vec::new()), + ToolType::Monofluid => Ok(Vec::new()), + ToolType::Difluid => Ok(Vec::new()), + ToolType::Trifluid => Ok(Vec::new()), + ToolType::HuntersReport => Ok(Vec::new()), ToolType::CellOfMag502 | ToolType::CellOfMag213 | ToolType::PartsOfRobochao @@ -268,6 +283,7 @@ where | ToolType::LibertaKit => { mag_cell(item_state, entity_gateway, character, entity_id, tool.try_into()?).await } + ToolType::JackOLantern => jack_o_lantern(item_state, entity_gateway).await, // TODO: rest of these _ => Err(ApplyItemError::InvalidItem) } @@ -275,7 +291,14 @@ where } -pub async fn apply_item<'a, EG: EntityGateway + ?Sized>(item_state: &mut ItemStateProxy<'a>, entity_gateway: &mut EG, character: &mut CharacterEntity, item: InventoryItem) -> Result<(), ApplyItemError> { +pub async fn apply_item<'a, EG>(item_state: &mut ItemStateProxy, + entity_gateway: &mut EG, + character: &mut CharacterEntity, + item: InventoryItem +) -> Result, ApplyItemError> +where + EG: EntityGateway + ?Sized + Clone + 'static +{ match item.item { InventoryItemDetail::Individual(individual_item) => { match individual_item.item { @@ -284,10 +307,22 @@ pub async fn apply_item<'a, EG: EntityGateway + ?Sized>(item_state: &mut ItemSta } }, InventoryItemDetail::Stacked(stacked_item) => { - for entity_id in stacked_item.entity_ids { - apply_tool(item_state, entity_gateway, character, entity_id, stacked_item.tool.tool).await? - } - Ok(()) + Ok(join_all(stacked_item.entity_ids.iter() + .map(|entity_id| { + let mut entity_gateway = entity_gateway.clone(); + let mut character = character.clone(); + let mut item_state = item_state.clone(); + async move { + apply_tool(&mut item_state, &mut entity_gateway, &mut character, *entity_id, stacked_item.tool.tool).await + } + }) + .collect::>()) + .await + .into_iter() + .collect::>, _>>()? + .into_iter() + .flatten() + .collect()) }, } } diff --git a/src/ship/items/state.rs b/src/ship/items/state.rs index 8c95391..0796997 100644 --- a/src/ship/items/state.rs +++ b/src/ship/items/state.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use async_std::sync::{Arc, RwLock}; +use async_std::sync::{Arc, RwLock, Mutex}; use futures::future::join_all; use crate::entity::gateway::{EntityGateway, GatewayError}; @@ -373,36 +373,38 @@ impl ItemState { } -#[derive(Default)] +#[derive(Default, Clone)] struct ProxiedItemState { - character_inventory: HashMap, - character_bank: HashMap, + character_inventory: Arc>>, + character_bank: Arc>>, //character_room: HashMap, - character_floor: HashMap, - room_floor: HashMap, + character_floor: Arc>>, + room_floor: Arc>>, } -pub struct ItemStateProxy<'a> { - item_state: &'a mut ItemState, +#[derive(Clone)] +pub struct ItemStateProxy { + item_state: ItemState, proxied_state: ProxiedItemState, } -impl<'a> ItemStateProxy<'a> { +impl ItemStateProxy { pub async fn commit(self) { async fn copy_back(master: &Arc>>>, - proxy: HashMap) + proxy: Arc>>) where K: Eq + std::hash::Hash, + V: Clone, { - for (key, value) in proxy { + for (key, value) in proxy.lock().await.iter() { if let Some(element) = master .read() .await .get(&key) { *element .write() - .await = value; + .await = value.clone(); } } } @@ -417,7 +419,7 @@ impl<'a> ItemStateProxy<'a> { async fn get_or_clone(master: &Arc>>>, - proxy: &mut HashMap, + proxy: &Arc>>, key: K, err: fn(K) -> ItemStateError) -> Result where @@ -432,14 +434,17 @@ where .read() .await .clone(); - Ok(proxy.entry(key) + Ok(proxy + .lock() + .await + .entry(key) .or_insert_with(|| existing_element) .clone()) } -impl<'a> ItemStateProxy<'a> { - pub fn new(item_state: &'a mut ItemState) -> Self { +impl ItemStateProxy { + pub fn new(item_state: ItemState) -> Self { ItemStateProxy { item_state, proxied_state: Default::default(), @@ -453,8 +458,8 @@ impl<'a> ItemStateProxy<'a> { ItemStateError::NoCharacter).await } - pub fn set_inventory(&mut self, inventory: InventoryState) { - self.proxied_state.character_inventory.insert(inventory.character_id, inventory); + pub async fn set_inventory(&mut self, inventory: InventoryState) { + self.proxied_state.character_inventory.lock().await.insert(inventory.character_id, inventory); } pub async fn bank(&mut self, character_id: &CharacterEntityId) -> Result { @@ -464,8 +469,8 @@ impl<'a> ItemStateProxy<'a> { ItemStateError::NoCharacter).await } - pub fn set_bank(&mut self, bank: BankState) { - self.proxied_state.character_bank.insert(bank.character_id, bank); + pub async fn set_bank(&mut self, bank: BankState) { + self.proxied_state.character_bank.lock().await.insert(bank.character_id, bank); } pub async fn floor(&mut self, character_id: &CharacterEntityId) -> Result { @@ -479,8 +484,8 @@ impl<'a> ItemStateProxy<'a> { pub async fn set_floor(&mut self, floor: FloorState) { let room_id = *self.item_state.character_room.read().await.get(&floor.character_id).unwrap(); - self.proxied_state.character_floor.insert(floor.character_id, floor.local); - self.proxied_state.room_floor.insert(room_id, floor.shared); + self.proxied_state.character_floor.lock().await.insert(floor.character_id, floor.local); + self.proxied_state.room_floor.lock().await.insert(room_id, floor.shared); } pub async fn new_item_id(&mut self) -> Result { diff --git a/src/ship/items/tasks.rs b/src/ship/items/tasks.rs index 844d116..1861bfc 100644 --- a/src/ship/items/tasks.rs +++ b/src/ship/items/tasks.rs @@ -1,13 +1,15 @@ use crate::ship::items::ClientItemId; use crate::entity::item::Meseta; +use crate::ship::ship::SendShipPacket; use crate::ship::map::MapArea; use crate::entity::character::{CharacterEntity, CharacterEntityId}; -use crate::entity::gateway::EntityGateway; +use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction}; use crate::ship::items::state::{ItemState, ItemStateProxy, ItemStateError, IndividualItemDetail}; use crate::ship::items::itemstateaction::{ItemStateAction, ItemAction}; use crate::ship::items::inventory::InventoryItem; use crate::ship::items::floor::FloorItem; +use crate::ship::items::apply_item::ApplyItemAction; use crate::entity::item::ItemModifier; use crate::ship::shops::ShopItem; use crate::ship::trade::TradeItem; @@ -23,10 +25,11 @@ pub async fn pick_up_item( item_id: &ClientItemId) -> Result where - EG: EntityGateway, + EG: EntityGateway + 'static, + EG::Transaction: Clone, { entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), result) = ItemStateAction::default() .act(actions::take_item_from_floor(character.id, *item_id)) .act(actions::add_floor_item_to_inventory(character)) @@ -46,10 +49,10 @@ pub async fn drop_item( drop_position: (f32, f32, f32)) -> Result where - EG: EntityGateway, + EG: EntityGateway + 'static, { entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), result) = ItemStateAction::default() .act(actions::take_item_from_inventory(character.id, *item_id, 0)) .act(actions::add_inventory_item_to_shared_floor(character.id, map_area, drop_position)) @@ -70,10 +73,10 @@ pub async fn drop_partial_item<'a, EG>( amount: u32) -> Result where - EG: EntityGateway, + EG: EntityGateway + 'static, { entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), result) = ItemStateAction::default() .act(actions::take_item_from_inventory(character.id, *item_id, amount)) .act(actions::add_inventory_item_to_shared_floor(character.id, map_area, (drop_position.0, 0.0, drop_position.1))) @@ -95,10 +98,10 @@ pub async fn drop_meseta<'a, EG>( amount: u32) -> Result where - EG: EntityGateway, + EG: EntityGateway + 'static, { entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), result) = ItemStateAction::default() .act(actions::take_meseta_from_inventory(character.id, amount)) .act(actions::add_meseta_to_shared_floor(character.id, amount, map_area, drop_position)) @@ -117,10 +120,10 @@ pub async fn withdraw_meseta<'a, EG>( amount: u32) -> Result<(), ItemStateError> where - EG: EntityGateway, + EG: EntityGateway + 'static, { entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), result) = ItemStateAction::default() .act(actions::take_meseta_from_bank(character.id, amount)) .act(actions::add_meseta_from_bank_to_inventory(character.id, amount)) @@ -139,10 +142,10 @@ pub async fn deposit_meseta<'a, EG>( amount: u32) -> Result<(), ItemStateError> where - EG: EntityGateway, + EG: EntityGateway + 'static, { entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), _) = ItemStateAction::default() .act(actions::take_meseta_from_inventory(character.id, amount)) .act(actions::add_meseta_to_bank(character.id, amount)) @@ -162,10 +165,10 @@ pub async fn withdraw_item<'a, EG>( amount: u32) -> Result where - EG: EntityGateway, + EG: EntityGateway + 'static, { entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), result) = ItemStateAction::default() .act(actions::take_item_from_bank(character.id, *item_id, amount)) //.act(bank_item_to_inventory_item) @@ -187,10 +190,10 @@ pub async fn deposit_item<'a, EG> ( amount: u32) -> Result<(), ItemStateError> where - EG: EntityGateway, + EG: EntityGateway + 'static, { entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), result) = ItemStateAction::default() .act(actions::take_item_from_inventory(character.id, *item_id, amount)) .act(actions::add_inventory_item_to_bank(character.id)) @@ -209,10 +212,10 @@ pub async fn equip_item<'a, EG> ( equip_slot: u8, ) -> Result<(), ItemStateError> where - EG: EntityGateway, + EG: EntityGateway + 'static, { entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), result) = ItemStateAction::default() .act(actions::equip_inventory_item(character.id, *item_id, equip_slot)) .commit((item_state_proxy, transaction)) @@ -230,10 +233,10 @@ pub async fn unequip_item<'a, EG> ( item_id: &ClientItemId, ) -> Result<(), ItemStateError> where - EG: EntityGateway, + EG: EntityGateway + 'static, { entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), result) = ItemStateAction::default() .act(actions::unequip_inventory_item(character.id, *item_id)) .commit((item_state_proxy, transaction)) @@ -251,10 +254,10 @@ pub async fn sort_inventory<'a, EG> ( item_ids: Vec, ) -> Result<(), ItemStateError> where - EG: EntityGateway, + EG: EntityGateway + 'static, { entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), result) = ItemStateAction::default() .act(actions::sort_inventory_items(character.id, item_ids)) .commit((item_state_proxy, transaction)) @@ -273,11 +276,11 @@ pub async fn use_item<'a, EG> ( amount: u32, ) -> Result<(), ItemStateError> where - EG: EntityGateway, + EG: EntityGateway + 'static, { entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); - let ((item_state_proxy, transaction), new_character) = ItemStateAction::default() + let item_state_proxy = ItemStateProxy::new(item_state.clone()); + let ((item_state_proxy, transaction), apply_item_actions) = ItemStateAction::default() .act(actions::take_item_from_inventory(character.id, *item_id, amount)) .act(actions::use_consumed_item(character.clone())) .commit((item_state_proxy, transaction)) @@ -297,10 +300,10 @@ pub async fn feed_mag<'a, EG> ( tool_item_id: &ClientItemId, ) -> Result<(), ItemStateError> where - EG: EntityGateway, + EG: EntityGateway + 'static, { entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), _) = ItemStateAction::default() .act(actions::take_item_from_inventory(character.id, *tool_item_id, 1)) .act(actions::feed_mag_item(character.clone(), *mag_item_id)) @@ -321,11 +324,11 @@ pub async fn buy_shop_item<'a, EG> ( amount: u32, ) -> Result where - EG: EntityGateway, + EG: EntityGateway + 'static, { let item_price = shop_item.price() as u32 * amount; entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), result) = ItemStateAction::default() .act(actions::take_meseta_from_inventory(character.id, item_price)) //.act(bought_item_to_inventory_item) @@ -347,10 +350,10 @@ pub async fn sell_item<'a, EG> ( amount: u32, ) -> Result where - EG: EntityGateway, + EG: EntityGateway + 'static, { entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), result) = ItemStateAction::default() .act(actions::take_item_from_inventory(character.id, item_id, amount)) .act(actions::sell_inventory_item(character.id)) @@ -367,7 +370,7 @@ pub async fn trade_items<'a, EG> ( p2: (&AreaClient, &CharacterEntity, &Vec, Meseta)) -> Result<(Vec, Vec), ItemStateError> where - EG: EntityGateway, + EG: EntityGateway + 'static, { let p1_trade_items = p1.2 .iter() @@ -391,7 +394,7 @@ where let p1_id = p1.1.id; let p2_id = p2.1.id; let trade = transaction.gateway().create_trade(&p1_id, &p2_id).await?; - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), p1_removed_items) = ItemStateAction::default() .act(actions::iterate(p1_trade_items, move |p1_trade_item| actions::take_item_from_inventory(p1_id, p1_trade_item.0, p1_trade_item.1) )) .act(actions::foreach(actions::assign_new_item_id())) @@ -437,10 +440,10 @@ pub async fn take_meseta<'a, EG> ( meseta: Meseta) -> Result<(), ItemStateError> where - EG: EntityGateway, + EG: EntityGateway + 'static, { entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), _) = ItemStateAction::default() .act(actions::take_meseta_from_inventory(*character_id, meseta.0)) .commit((item_state_proxy, transaction)) @@ -458,10 +461,10 @@ pub async fn enemy_drops_item<'a, EG> ( item_drop: ItemDrop) -> Result where - EG: EntityGateway, + EG: EntityGateway + 'static, { entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), floor_item) = ItemStateAction::default() .act(actions::convert_item_drop_to_floor_item(character_id, item_drop)) .act(actions::add_item_to_local_floor(character_id)) @@ -482,10 +485,10 @@ pub async fn apply_modifier<'a, EG> ( modifier: ItemModifier) -> Result where - EG: EntityGateway, + EG: EntityGateway + 'static, { entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); + let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), item) = ItemStateAction::default() .act(actions::take_item_from_inventory(character.id, item_id, 1)) .act(actions::apply_modifier_to_inventory_item(modifier)) diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index f565d41..5c49a53 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -84,7 +84,7 @@ pub async fn request_item(id: ClientId, item_state: &mut ItemState) -> Result, ShipError> where - EG: EntityGateway + EG: EntityGateway + 'static, { let room_id = client_location.get_room(id).await?; let monster = rooms.with(room_id, |room| Box::pin(async move {