From 11b5898637cffb263c29d22a864e938f90fd941d Mon Sep 17 00:00:00 2001 From: jake Date: Wed, 27 Apr 2022 20:57:47 -0600 Subject: [PATCH] move item state action functions to new file --- src/ship/items/actions.rs | 314 ++++++++++++++++++++++++++++++++++++++ src/ship/items/mod.rs | 1 + src/ship/items/state.rs | 279 +++++++++++++++++++-------------- 3 files changed, 478 insertions(+), 116 deletions(-) create mode 100644 src/ship/items/actions.rs diff --git a/src/ship/items/actions.rs b/src/ship/items/actions.rs new file mode 100644 index 0000000..934fac7 --- /dev/null +++ b/src/ship/items/actions.rs @@ -0,0 +1,314 @@ +use std::collections::HashMap; +use crate::ship::items::ClientItemId; +use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, ItemType, InventoryEntity, InventoryItemEntity, EquippedEntity, ItemNote}; +use std::cell::{RefMut, RefCell}; +use std::ops::{Deref, DerefMut}; +use std::convert::{From, Into}; +use std::future::Future; +use std::pin::Pin; +use async_std::sync::{Arc, Mutex}; +use std::borrow::BorrowMut; + +use crate::ship::location::{AreaClient, RoomId}; +use crate::entity::character::{CharacterEntity, CharacterEntityId, TechLevel}; +use crate::entity::gateway::{EntityGateway, GatewayError}; +use crate::entity::gateway::entitygateway::EntityGatewayTransaction; +use crate::entity::item::tool::{Tool, ToolType}; +use crate::ship::items::state::{ItemState, ItemStateProxy, ItemStateAction, ItemAction, ItemStateError, FloorItem, InventoryItem, AddItemResult}; + +pub enum TriggerCreateItem {ItemAction, + Yes, + No +} + +/* +fn take_item_from_floor(character_id: CharacterEntityId, item_id: ClientItemId) + -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) + -> Pin), FloorItem), ItemStateError>> + Send + 'a>> +{ + move |(mut item_state, transaction), _| { + Box::pin(async move { + let mut floor = item_state.floor(&character_id)?; + let item = floor.take_item(&item_id).ok_or(ItemStateError::NoFloorItem(item_id))?; + item_state.set_floor(floor); + + Ok(((item_state, transaction), item)) + }) + } +} +*/ + +fn take_item_from_floor(character_id: CharacterEntityId, item_id: ClientItemId) + -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) + -> Pin), FloorItem), ItemStateError>> + Send + 'a>> +{ + move |(mut item_state, transaction), _| { + Box::pin(async move { + let mut floor = item_state.floor(&character_id)?; + let item = floor.take_item(&item_id).ok_or(ItemStateError::NoFloorItem(item_id))?; + item_state.set_floor(floor); + + Ok(((item_state, transaction), item)) + }) + } +} + +/* +fn take_item_from_floor<'a, F, Fut>(character_id: CharacterEntityId, item_id: ClientItemId) -> F +where + F: Fn((ItemStateProxy<'a>, Box), ()) -> Fut, + Fut: Future, Box), FloorItem), ItemStateError>> + Send + //Fut: Result, Box), FloorItem)> + Send, ItemStateError> + +{ + async move |(mut item_state, transaction): (ItemStateProxy<'a>, Box), _: ()| { + let mut floor = item_state.floor(&character_id)?; + let item = floor.take_item(&item_id).ok_or(ItemStateError::NoFloorItem(item_id))?; + item_state.set_floor(floor); + + Ok(((item_state, transaction), item)) + } +} +*/ + +/* +fn add_floor_item_to_inventory<'a, Fut>(character: &CharacterEntity) + -> impl Fn((ItemStateProxy<'a>, Box), FloorItem) -> Fut +where + Fut: Future, Box), TriggerCreateItem), ItemStateError>> + Send +{ + let character = character.clone(); + move |(mut item_state, transaction): (ItemStateProxy<'a>, Box), floor_item: FloorItem| { + let character = character.clone(); + async move { + let mut inventory = item_state.inventory(&character.id)?; + + let character_id = character.id; + let transaction = floor_item.with_entity_id(Ok(transaction), |mut transaction: Result<_, ItemStateError>, entity_id| { + async move { + if let Ok(transaction) = &mut transaction { + transaction.gateway().add_item_note(&entity_id, ItemNote::Pickup { + character_id + }).await?; + } + transaction + }}).await?; + + let mut transaction = floor_item.with_mag(Ok(transaction), |mut transaction: Result<_, ItemStateError>, entity_id, _mag| { + let character = character.clone(); + async move { + if let Ok(transaction) = &mut transaction { + transaction.gateway().change_mag_owner(&entity_id, &character).await?; + } + transaction + }}).await?; + + let add_result = inventory.add_floor_item(floor_item)?; + transaction.gateway().set_character_inventory(&character.id, &inventory.inventory.as_inventory_entity(&character.id)).await?; + item_state.set_inventory(inventory); + + Ok(((item_state, transaction), + match add_result { + AddItemResult::NewItem => TriggerCreateItem::Yes, + AddItemResult::AddToStack => TriggerCreateItem::No, + AddItemResult::Meseta => TriggerCreateItem::No, + })) + } + } +} +*/ + +fn add_floor_item_to_inventory(character: &CharacterEntity) + -> impl for<'a> Fn((ItemStateProxy<'a>, Box), FloorItem) + -> Pin), TriggerCreateItem), ItemStateError>> + Send + 'a>> +{ + let character = character.clone(); + move |(mut item_state, transaction), floor_item| { + let character = character.clone(); + Box::pin(async move { + let mut inventory = item_state.inventory(&character.id)?; + + let character_id = character.id; + let transaction = floor_item.with_entity_id(Ok(transaction), |mut transaction: Result<_, ItemStateError>, entity_id| { + async move { + if let Ok(transaction) = &mut transaction { + transaction.gateway().add_item_note(&entity_id, ItemNote::Pickup { + character_id + }).await?; + } + transaction + }}).await?; + + let mut transaction = floor_item.with_mag(Ok(transaction), |mut transaction: Result<_, ItemStateError>, entity_id, _mag| { + let character = character.clone(); + async move { + if let Ok(transaction) = &mut transaction { + transaction.gateway().change_mag_owner(&entity_id, &character).await?; + } + transaction + }}).await?; + + let add_result = inventory.add_floor_item(floor_item)?; + transaction.gateway().set_character_inventory(&character.id, &inventory.inventory.as_inventory_entity(&character.id)).await?; + item_state.set_inventory(inventory); + + Ok(((item_state, transaction), + match add_result { + AddItemResult::NewItem => TriggerCreateItem::Yes, + AddItemResult::AddToStack => TriggerCreateItem::No, + AddItemResult::Meseta => TriggerCreateItem::No, + })) + }) + } +} + +/* +fn add_floor_item_to_inventory(character: &CharacterEntity) + -> impl for<'a> Fn((ItemStateProxy<'a>, Box), FloorItem) + -> Pin), TriggerCreateItem), ItemStateError>> + Send + 'a>> +{ + let character = character.clone(); + move |(mut item_state, transaction), floor_item| { + let character = character.clone(); + Box::pin(async move { + let mut inventory = item_state.inventory(&character.id)?; + + let character_id = character.id; + let transaction = floor_item.with_entity_id(Ok(transaction), |mut transaction: Result<_, ItemStateError>, entity_id| { + async move { + if let Ok(transaction) = &mut transaction { + transaction.gateway().add_item_note(&entity_id, ItemNote::Pickup { + character_id + }).await?; + } + transaction + }}).await?; + + let mut transaction = floor_item.with_mag(Ok(transaction), |mut transaction: Result<_, ItemStateError>, entity_id, _mag| { + let character = character.clone(); + async move { + if let Ok(transaction) = &mut transaction { + transaction.gateway().change_mag_owner(&entity_id, &character).await?; + } + transaction + }}).await?; + + let add_result = inventory.add_floor_item(floor_item)?; + transaction.gateway().set_character_inventory(&character.id, &inventory.inventory.as_inventory_entity(&character.id)).await?; + item_state.set_inventory(inventory); + + Ok(((item_state, transaction), + match add_result { + AddItemResult::NewItem => TriggerCreateItem::Yes, + AddItemResult::AddToStack => TriggerCreateItem::No, + AddItemResult::Meseta => TriggerCreateItem::No, + })) + }) + } +} +*/ + +/* +fn take_item_from_inventory(character_id: CharacterEntityId, item_id: ClientItemId) + -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) + -> Pin), InventoryItem), ItemStateError>> + Send + 'a>> +{ + move |(mut item_state, transaction), _| { + Box::pin(async move { + let mut inventory = item_state.inventory(&character_id)?; + let item = inventory.take_item(&item_id); + + transaction.gateway().set_character_inventory(&character_id, &inventory.inventory.as_inventory_entity(&character_id)).await?; + item_state.set_inventory(inventory); + Ok((item_state, transaction), item) + }) + } +} + + +fn add_inventory_item_to_shared_floor(character: &CharacterEntity) + -> impl for<'a> Fn((ItemStateProxy<'a>, Box), InventoryItem) + -> Pin), ()), ItemStateError>> + Send + 'a>> +{ + let character = character.clone(); + move |(mut item_state, transaction), inventory_item| { + let character = character.clone(); + Box::pin(async move { + + }) + } +} +*/ + +/* +pub async fn pick_up_item<'a, EG>( + item_state: &'a mut ItemState, + entity_gateway: &mut EG, + character: &CharacterEntity, + item_id: &ClientItemId) + -> Result +where + //'a: 'static, + EG: EntityGateway, +{ + let result: Result = entity_gateway.with_transaction(|transaction| async move { + let item_state_proxy = ItemStateProxy::new(item_state); + let ((item_state_proxy, transaction), result) = ItemStateAction::default() + .act(take_item_from_floor(character.id, *item_id)) + .act(add_floor_item_to_inventory(character)) + .commit((item_state_proxy, transaction)) + .await?; + item_state_proxy.commit(); + Ok((transaction, result)) + }).await; + Ok(result?) +} +*/ + +pub async fn pick_up_item( + item_state: &mut ItemState, + entity_gateway: &mut EG, + character: &CharacterEntity, + item_id: &ClientItemId) + -> Result +where + EG: EntityGateway, +{ + let result: Result = entity_gateway.with_transaction(|transaction| async move { + let item_state_proxy = ItemStateProxy::new(item_state); + let ((item_state_proxy, transaction), result) = ItemStateAction::default() + .act(take_item_from_floor(character.id, *item_id)) + .act(add_floor_item_to_inventory(character)) + .commit((item_state_proxy, transaction)) + .await?; + item_state_proxy.commit(); + Ok((transaction, result)) + }).await; + Ok(result?) +} + +pub async fn drop_item( + item_state: &mut ItemState, + entity_gateway: &mut EG, + character: &CharacterEntity, + item_id: &ClientItemId) + -> Result<(), ItemStateError> +where + //'a: 'static, + EG: EntityGateway, +{ +/* + let result: Result = entity_gateway.with_transaction(|transaction| async move { + let item_state_proxy = ItemStateProxy::new(item_state); + let ((item_state_proxy, transaction), result) = ItemStateAction::default() + .act(take_item_from_inventory(character.id, *item_id)) + .act(add_inventory_item_to_shared_floor(&character)) + .commit((item_state_proxy, transaction)) + .await?; + item_state_proxy.commit(); + Ok((transaction, result)) + }).await; + Ok(result?) + */ + Ok(()) +} diff --git a/src/ship/items/mod.rs b/src/ship/items/mod.rs index 2b88239..b37db38 100644 --- a/src/ship/items/mod.rs +++ b/src/ship/items/mod.rs @@ -5,6 +5,7 @@ pub mod manager; pub mod transaction; pub mod use_tool; pub mod state; +pub mod actions; use serde::{Serialize, Deserialize}; #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, derive_more::Display)] diff --git a/src/ship/items/state.rs b/src/ship/items/state.rs index b31ed9c..323505d 100644 --- a/src/ship/items/state.rs +++ b/src/ship/items/state.rs @@ -14,16 +14,12 @@ use crate::entity::character::{CharacterEntity, CharacterEntityId, TechLevel}; use crate::entity::gateway::{EntityGateway, GatewayError}; use crate::entity::gateway::entitygateway::EntityGatewayTransaction; use crate::entity::item::tool::{Tool, ToolType}; +use crate::entity::item::mag::Mag; use crate::ship::drops::ItemDrop; -pub enum TriggerCreateItem { - Yes, - No -} - #[derive(thiserror::Error, Debug)] -enum ItemStateError { +pub enum ItemStateError { #[error("character {0} not found")] NoCharacter(CharacterEntityId), #[error("room {0} not found")] @@ -46,7 +42,7 @@ enum ItemStateError { #[async_trait::async_trait] -trait ItemAction { +pub trait ItemAction { type Input; type Output; type Start; @@ -57,7 +53,7 @@ trait ItemAction { } -struct ItemStateAction { +pub struct ItemStateAction { _t: std::marker::PhantomData, _s: std::marker::PhantomData, _e: std::marker::PhantomData, @@ -185,20 +181,20 @@ where } -#[derive(Clone)] -struct IndividualItemDetail { +#[derive(Clone, Debug)] +pub struct IndividualItemDetail { entity_id: ItemEntityId, item: ItemDetail, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct StackedItemDetail { pub entity_ids: Vec, pub tool: Tool, } -#[derive(Clone)] -enum InventoryItemDetail { +#[derive(Clone, Debug)] +pub enum InventoryItemDetail { Individual(IndividualItemDetail), Stacked(StackedItemDetail), } @@ -219,14 +215,35 @@ impl InventoryItemDetail { } -#[derive(Clone)] -struct InventoryItem { +#[derive(Clone, Debug)] +pub struct InventoryItem { item_id: ClientItemId, item: InventoryItemDetail, } +impl InventoryItem { + pub async fn with_entity_id(&self, mut param: T, mut func: F) -> T + where + F: FnMut(T, ItemEntityId) -> Fut, + Fut: Future, + { + match &self.item { + InventoryItemDetail::Individual(individual_item) => { + param = func(param, individual_item.entity_id.clone()).await; + }, + InventoryItemDetail::Stacked(stacked_item) => { + for entity_id in &stacked_item.entity_ids { + param = func(param, entity_id.clone()).await; + } + } + } + + param + } +} + #[derive(Clone)] -enum FloorItemDetail { +pub enum FloorItemDetail { Individual(IndividualItemDetail), Stacked(StackedItemDetail), Meseta(Meseta), @@ -239,14 +256,70 @@ impl FloorItemDetail { _ => None, } } + + /* + fn mag<'a>(&'a self) -> Option<&'a IndividualItemDetail> { + match self { + FloorItemDetail::Individual(individual_item) => { + match individual_item.item { + ItemDetail::Mag(mag) => Some(mag), + _ => None, + } + }, + _ => None + } + } +*/ } #[derive(Clone)] -struct FloorItem { +pub struct FloorItem { item_id: ClientItemId, item: FloorItemDetail, } +impl FloorItem { + pub async fn with_entity_id(&self, mut param: T, mut func: F) -> T + where + F: FnMut(T, ItemEntityId) -> Fut, + Fut: Future, + { + match &self.item { + FloorItemDetail::Individual(individual_item) => { + param = func(param, individual_item.entity_id.clone()).await; + }, + FloorItemDetail::Stacked(stacked_item) => { + for entity_id in &stacked_item.entity_ids { + param = func(param, entity_id.clone()).await; + } + }, + FloorItemDetail::Meseta(_meseta) => {}, + } + + param + } + + pub async fn with_mag(&self, mut param: T, mut func: F) -> T + where + F: FnMut(T, ItemEntityId, Mag) -> Fut, + Fut: Future, + { + match &self.item { + FloorItemDetail::Individual(individual_item) => { + match &individual_item.item { + ItemDetail::Mag(mag) => { + param = func(param, individual_item.entity_id.clone(), mag.clone()).await; + } + _ => {} + } + }, + _ => {} + } + + param + } +} + // meseta is a floor item /* impl Into for FloorItem { @@ -259,12 +332,49 @@ impl Into for FloorItem { } */ -#[derive(Clone)] -struct Inventory(Vec); +#[derive(Clone, Debug)] +pub struct Inventory(Vec); +/* +#[derive(Clone, Debug)] +pub struct Inventory { + item_id_counter: u32, + items: Vec, + equipped: EquippedEntity, +} +*/ + +impl Inventory { + pub fn as_inventory_entity(&self, _character_id: &CharacterEntityId) -> InventoryEntity { + InventoryEntity { + items: self.0.iter() + .map(|item| { + match &item.item { + InventoryItemDetail::Individual(item) => { + InventoryItemEntity::Individual(ItemEntity { + id: item.entity_id, + item: item.item.clone(), + }) + }, + InventoryItemDetail::Stacked(items) => { + InventoryItemEntity::Stacked(items.entity_ids.iter() + .map(|id| { + ItemEntity { + id: *id, + item: ItemDetail::Tool(items.tool) + } + }) + .collect()) + }, + } + }) + .collect() + } + } +} #[derive(thiserror::Error, Debug)] -enum InventoryError { +pub enum InventoryError { #[error("inventory full")] InventoryFull, #[error("stack full")] @@ -273,49 +383,27 @@ enum InventoryError { MesetaFull, } -enum AddItemResult { +pub enum AddItemResult { NewItem, AddToStack, Meseta, } - - - - #[derive(Clone)] -struct LocalFloor(Vec); +pub struct LocalFloor(Vec); #[derive(Clone)] -struct SharedFloor(Vec); +pub struct SharedFloor(Vec); #[derive(Clone)] -struct RoomFloorItems(Vec); +pub struct RoomFloorItems(Vec); -struct InventoryState { +pub struct InventoryState { character_id: CharacterEntityId, - inventory: Inventory, + pub inventory: Inventory, meseta: Meseta, } - -/* -impl Deref for InventoryState { - type Target = Inventory; - - fn deref(&self) -> &Self::Target { - &self.inventory - } -} - - -impl DerefMut for InventoryState { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inventory - } -} -*/ - impl InventoryState { - 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 { @@ -374,14 +462,14 @@ impl InventoryState { } } -struct FloorState { +pub struct FloorState { character_id: CharacterEntityId, local: LocalFloor, shared: SharedFloor, } impl FloorState { - fn take_item(&mut self, item_id: &ClientItemId) -> Option { + pub fn take_item(&mut self, item_id: &ClientItemId) -> Option { let item = self.local.0 .drain_filter(|item| { item.item_id == *item_id @@ -398,7 +486,7 @@ impl FloorState { } -struct ItemState { +pub struct ItemState { character_inventory: HashMap, //character_bank: HashMap, character_meseta: HashMap, @@ -485,19 +573,31 @@ impl Default for ProxiedItemState { } } -struct ItemStateProxy<'a> { +pub struct ItemStateProxy<'a> { item_state: &'a mut ItemState, //entity_gateway: &'a mut dyn EntityGateway, - transaction: Box, + //transaction: Box, //entity_gateway: &'a mut Box, //entity_gateway: &'a mut Box, proxied_state: ProxiedItemState, - gateway_actions: Vec, + //gateway_actions: Vec, //_eg: std::marker::PhantomData, } +//impl<'a> Drop for ItemStateProxy<'a> { +// fn drop(&mut self) { +impl<'a> ItemStateProxy<'a> { + pub fn commit(self) { + self.item_state.character_inventory.extend(self.proxied_state.character_inventory.clone()); + self.item_state.character_meseta.extend(self.proxied_state.character_meseta.clone()); + self.item_state.character_room.extend(self.proxied_state.character_room.clone()); + self.item_state.character_floor.extend(self.proxied_state.character_floor.clone()); + self.item_state.room_floor.extend(self.proxied_state.room_floor.clone()); + } +} + /* fn get_or_clone<'a, K, V>(master: &HashMap, proxy: &'a RefCell>>, key: K, err: fn(K) -> ItemStateError) -> Result + 'a, ItemStateError> where @@ -541,18 +641,18 @@ where impl<'a> ItemStateProxy<'a> { //fn new(item_state: &'a mut ItemState, entity_gateway: &'a mut EG) -> Self { //fn new(item_state: &'a mut ItemState, entity_gateway: &'a mut dyn EntityGateway) -> Self { - fn new(item_state: &'a mut ItemState, transaction: Box) -> Self { + pub fn new(item_state: &'a mut ItemState/*, transaction: Box*/) -> Self { ItemStateProxy { item_state, //entity_gateway, - transaction, + //transaction, proxied_state: Default::default(), - gateway_actions: Vec::new(), + //gateway_actions: Vec::new(), //_eg: std::marker::PhantomData, } } - fn inventory(&mut self, character_id: &CharacterEntityId) -> Result { + pub fn inventory(&mut self, character_id: &CharacterEntityId) -> Result { Ok(InventoryState { character_id: *character_id, inventory: get_or_clone(&self.item_state.character_inventory, &mut self.proxied_state.character_inventory, *character_id, |c| ItemStateError::NoCharacter(c))?, @@ -560,12 +660,12 @@ impl<'a> ItemStateProxy<'a> { }) } - fn set_inventory(&mut self, inventory: InventoryState) { + pub fn set_inventory(&mut self, inventory: InventoryState) { self.proxied_state.character_inventory.insert(inventory.character_id, inventory.inventory); self.proxied_state.character_meseta.insert(inventory.character_id, inventory.meseta); } - fn floor(&mut self, character_id: &CharacterEntityId) -> Result { + pub fn floor(&mut self, character_id: &CharacterEntityId) -> Result { let room_id = get_or_clone(&self.item_state.character_room, &mut self.proxied_state.character_room, *character_id, |c| ItemStateError::NoCharacter(c))?; Ok(FloorState { character_id: *character_id, @@ -574,13 +674,13 @@ impl<'a> ItemStateProxy<'a> { }) } - fn set_floor(&mut self, floor: FloorState) { + pub fn set_floor(&mut self, floor: FloorState) { let room_id = get_or_clone(&self.item_state.character_room, &mut self.proxied_state.character_room, floor.character_id, |c| ItemStateError::NoCharacter(c)).unwrap(); self.proxied_state.character_floor.insert(floor.character_id, floor.local); self.proxied_state.room_floor.insert(room_id, floor.shared); } - fn new_item_id(&mut self) -> Result { + pub fn new_item_id(&mut self) -> Result { //let room_id = get_or_clone(&self.item_state.character_room, &mut self.proxied_state.character_room, *character_id, |c| ItemStateError::NoCharacter(c))?; self.item_state.room_item_id_counter += 1; Ok(ClientItemId(self.item_state.room_item_id_counter)) @@ -595,59 +695,6 @@ impl<'a> ItemStateProxy<'a> { } -fn take_item_from_floor(character_id: CharacterEntityId, item_id: ClientItemId) - -> impl for<'a> Fn(ItemStateProxy<'a>, ()) - -> Pin> + Send + 'a>> { - move |mut item_state, _| { - Box::pin(async move { - let mut floor = item_state.floor(&character_id)?; - let item = floor.take_item(&item_id).ok_or(ItemStateError::NoFloorItem(item_id))?; - item_state.set_floor(floor); - Ok((item_state, item)) - }) - } -} - -fn add_floor_item_to_inventory(character_id: CharacterEntityId) - -> impl for<'a> Fn(ItemStateProxy<'a>, FloorItem) - -> Pin> + Send + 'a>> { - move |mut item_state, floor_item| Box::pin(async move { - let mut inventory = item_state.inventory(&character_id)?; - let add_result = inventory.add_floor_item(floor_item)?; - item_state.set_inventory(inventory); - Ok((item_state, - match add_result { - AddItemResult::NewItem => TriggerCreateItem::Yes, - AddItemResult::AddToStack => TriggerCreateItem::No, - AddItemResult::Meseta => TriggerCreateItem::No, - })) - }) -} - - -#[fix_hidden_lifetime_bug] -async fn pick_up_item<'a, EG>( - item_state: &'a mut ItemState, - entity_gateway: &'a mut EG, - character_id: &CharacterEntityId, - item_id: &ClientItemId) - -> Result -where - 'a: 'static, - EG: EntityGateway, -{ - let result: Result = entity_gateway.with_transaction(|transaction| async move { - let item_state_proxy = ItemStateProxy::new(item_state); - let ((item_state_proxy, transaction), result) = ItemStateAction::default() - .act(take_item_from_floor(*character_id, *item_id)) - .act(add_floor_item_to_inventory(*character_id)) - .commit((item_state_proxy, transaction)) - .await?; - Ok((transaction, result)) - }).await; - Ok(result?) -} - /* fn record_item_drop(character_id: CharacterEntityId, item_drop: ItemDrop) -> impl Fn(&mut ItemStateProxy, ()) -> Result<(), ItemStateError> {