initial ItemState
This commit is contained in:
		
							parent
							
								
									283688832b
								
							
						
					
					
						commit
						1ef0231d93
					
				| @ -32,4 +32,4 @@ sqlx = { version = "0.5.10", features = ["runtime-async-std-native-tls", "postgr | ||||
| strum = "0.19.5" | ||||
| strum_macros = "0.19" | ||||
| anyhow = { version = "1.0.47", features = ["backtrace"] } | ||||
| 
 | ||||
| fix-hidden-lifetime-bug = "0.2.4" | ||||
|  | ||||
| @ -3,6 +3,8 @@ | ||||
| #![feature(drain_filter)] | ||||
| #![feature(try_blocks)] | ||||
| 
 | ||||
| #[macro_use] | ||||
| extern crate fix_hidden_lifetime_bug; | ||||
| 
 | ||||
| 
 | ||||
| pub mod common; | ||||
|  | ||||
| @ -4,6 +4,7 @@ pub mod inventory; | ||||
| pub mod manager; | ||||
| pub mod transaction; | ||||
| pub mod use_tool; | ||||
| pub mod state; | ||||
| use serde::{Serialize, Deserialize}; | ||||
| 
 | ||||
| #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, derive_more::Display)] | ||||
|  | ||||
							
								
								
									
										813
									
								
								src/ship/items/state.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										813
									
								
								src/ship/items/state.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,813 @@ | ||||
| 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::drops::ItemDrop; | ||||
| 
 | ||||
| pub enum TriggerCreateItem { | ||||
|     Yes, | ||||
|     No | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug)] | ||||
| enum ItemStateError { | ||||
|     #[error("character {0} not found")] | ||||
|     NoCharacter(CharacterEntityId), | ||||
|     #[error("room {0} not found")] | ||||
|     NoRoom(RoomId), | ||||
|     #[error("floor item {0} not found")] | ||||
|     NoFloorItem(ClientItemId), | ||||
| 
 | ||||
|     #[error("inventory error {0}")] | ||||
|     InventoryError(#[from] InventoryError), | ||||
| 
 | ||||
|     #[error("invalid drop? {0:?} (this shouldn't occur)")] | ||||
|     BadItemDrop(ItemDrop), | ||||
| 
 | ||||
|     #[error("idk")] | ||||
|     Dummy, | ||||
| 
 | ||||
|     #[error("gateway")] | ||||
|     GatewayError(GatewayError), | ||||
| } | ||||
| 
 | ||||
| impl From<GatewayError> for ItemStateError { | ||||
|     fn from(other: GatewayError) -> ItemStateError { | ||||
|         ItemStateError::GatewayError(other) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| enum GatewayActions { | ||||
|     ItemNote(ItemEntityId, ItemNote), | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| enum ItemStateChange { | ||||
|     Inventory(CharacterInventory), | ||||
|     Bank(CharacterBank), | ||||
|     CharacterMeseta(CharacterMeseta), | ||||
|     BankMeseta(BankMeseta), | ||||
|     SharedFloor(SharedFloor), | ||||
|     LocalFloor(LocalFloor), | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| #[async_trait::async_trait] | ||||
| trait ItemAction { | ||||
|     type Input; | ||||
|     type Output; | ||||
|     type Start; | ||||
|     type Error; | ||||
| 
 | ||||
|     async fn action(&self, s: Self::Start, i: Self::Input) -> Result<(Self::Start, Self::Output), Self::Error>; | ||||
|     async fn commit(&self, v: Self::Start) -> Result<(Self::Start, Self::Output), Self::Error>; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| struct ItemStateAction<T, S, E> { | ||||
|     _t: std::marker::PhantomData<T>, | ||||
|     _s: std::marker::PhantomData<S>, | ||||
|     _e: std::marker::PhantomData<E>, | ||||
| } | ||||
| 
 | ||||
| impl<T, S, E> Default for ItemStateAction<T, S, E> { | ||||
|     fn default() -> ItemStateAction<T, S, E> { | ||||
|         ItemStateAction { | ||||
|             _t: std::marker::PhantomData, | ||||
|             _s: std::marker::PhantomData, | ||||
|             _e: std::marker::PhantomData, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T, S, E> ItemStateAction<T, S, E> | ||||
| where | ||||
|     T: Send + Sync, | ||||
|     S: Send + Sync, | ||||
|     E: Send + Sync, | ||||
| { | ||||
|     fn act<O, F>(self, f: F) -> ItemActionStage<O, ItemStateAction<T, S, E>, F, S, E> | ||||
|     where | ||||
|         F: Fn(S, ()) -> Pin<Box<dyn Future<Output=Result<(S, O), E>> + Send>> + Send + Sync | ||||
|     { | ||||
|         ItemActionStage { | ||||
|             _s: Default::default(), | ||||
|             _e: std::marker::PhantomData, | ||||
|             prev: self, | ||||
|             actionf: f, | ||||
|             //actionf: |s, t| f(s, ()),
 | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| struct ItemActionStage<O, P, F, S, E> | ||||
| where | ||||
|     P: ItemAction, | ||||
|     //F: Fn(&mut S, P::Output) -> Result<O, E> + for<'r> std::ops::Fn<(&'r mut S, T)>,
 | ||||
|     F: Fn(S, P::Output) -> Pin<Box<dyn Future<Output=Result<(S, O) , E>> + Send>> + Send + Sync, | ||||
| { | ||||
|     _s: std::marker::PhantomData<S>, | ||||
|     _e: std::marker::PhantomData<E>, | ||||
|     prev: P, | ||||
|     actionf: F, | ||||
| } | ||||
| 
 | ||||
| #[async_trait::async_trait] | ||||
| impl<O, P: ItemAction, F, S, E> ItemAction for ItemActionStage<O, P, F, S, E> | ||||
| where | ||||
|     P: ItemAction + ItemAction<Start = S, Error = E> + Send + Sync, | ||||
|     F: Fn(S, P::Output) -> Pin<Box<dyn Future<Output=Result<(S, O), E>> + Send>> + Send + Sync, | ||||
|     S: Send + Sync, | ||||
|     P::Output: Send + Sync, | ||||
|     E: Send + Sync, | ||||
|     O: Send + Sync, | ||||
|     P::Error: Send + Sync, | ||||
| { | ||||
|     type Input = P::Output; | ||||
|     type Output = O; | ||||
|     type Start = S; | ||||
|     type Error = P::Error; | ||||
| 
 | ||||
|     async fn action(&self, s: Self::Start, i: Self::Input) -> Result<(Self::Start, Self::Output), Self::Error> { | ||||
|         (self.actionf)(s, i).await | ||||
|     } | ||||
| 
 | ||||
|     async fn commit(&self, i: Self::Start) -> Result<(Self::Start, Self::Output), Self::Error> { | ||||
|         let (i, prev) = self.prev.commit(i).await?; | ||||
|         self.action(i, prev).await | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<O, P: ItemAction, F, S, E> ItemActionStage<O, P, F, S, E> | ||||
| where | ||||
|     P: ItemAction<Start = S, Error = E> + Send + Sync, | ||||
|     F: Fn(S, P::Output) -> Pin<Box<dyn Future<Output=Result<(S, O), E>> + Send>> + Send + Sync, | ||||
|     S: Send + Sync, | ||||
|     P::Output: Send + Sync, | ||||
|     E: Send + Sync, | ||||
|     O: Send + Sync, | ||||
|     P::Error: Send + Sync, | ||||
| { | ||||
|     fn act<O2, G>(self, g: G) -> ItemActionStage<O2, ItemActionStage<O, P, F, S, E>, G, S, E> | ||||
|     where | ||||
|         S: Send + Sync, | ||||
|         G: Fn(S, <ItemActionStage<O, P, F, S, E> as ItemAction>::Output) -> Pin<Box<dyn Future<Output=Result<(S, O2), E>> + Send>> + Send + Sync, | ||||
|         O2: Send + Sync, | ||||
|     { | ||||
|         ItemActionStage { | ||||
|             _s: Default::default(), | ||||
|             _e: Default::default(), | ||||
|             prev: self, | ||||
|             actionf: g, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[async_trait::async_trait] | ||||
| impl<T, S, E> ItemAction for ItemStateAction<T, S, E> | ||||
| where | ||||
|     T: Send + Sync, | ||||
|     S: Send + Sync, | ||||
|     E: Send + Sync, | ||||
| { | ||||
|     type Input = T; | ||||
|     type Output = (); | ||||
|     type Start = T; | ||||
|     type Error = E; | ||||
| 
 | ||||
|     async fn action(&self, s: Self::Start, i: Self::Input) -> Result<(Self::Start, Self::Output), Self::Error> { | ||||
|         Ok((s, ())) | ||||
|     } | ||||
| 
 | ||||
|     async fn commit(&self, i: Self::Start) -> Result<(Self::Start, Self::Output), Self::Error> { | ||||
|         Ok((i, ())) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| struct IndividualItemDetail { | ||||
|     entity_id: ItemEntityId, | ||||
|     item: ItemDetail, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub struct StackedItemDetail { | ||||
|     pub entity_ids: Vec<ItemEntityId>, | ||||
|     pub tool: Tool, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| enum InventoryItemDetail { | ||||
|     Individual(IndividualItemDetail), | ||||
|     Stacked(StackedItemDetail), | ||||
| } | ||||
| 
 | ||||
| impl InventoryItemDetail { | ||||
|     fn stacked<'a>(&'a self) -> Option<&'a StackedItemDetail> { | ||||
|         match self { | ||||
|             InventoryItemDetail::Stacked(sitem) => Some(sitem), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
|     fn stacked_mut <'a>(&'a mut self) -> Option<&'a mut StackedItemDetail> { | ||||
|         match self { | ||||
|             InventoryItemDetail::Stacked(sitem) => Some(sitem), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| struct InventoryItem { | ||||
|     item_id: ClientItemId, | ||||
|     item: InventoryItemDetail, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| enum FloorItemDetail { | ||||
|     Individual(IndividualItemDetail), | ||||
|     Stacked(StackedItemDetail), | ||||
|     Meseta(Meseta), | ||||
| } | ||||
| 
 | ||||
| impl FloorItemDetail { | ||||
|     fn stacked<'a>(&'a self) -> Option<&'a StackedItemDetail> { | ||||
|         match self { | ||||
|             FloorItemDetail::Stacked(sitem) => Some(sitem), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| struct FloorItem { | ||||
|     item_id: ClientItemId, | ||||
|     item: FloorItemDetail, | ||||
| } | ||||
| 
 | ||||
| // meseta is a floor item
 | ||||
| /* | ||||
| impl Into<InventoryItem> for FloorItem { | ||||
|     fn into(&self) -> InventoryItem { | ||||
|         InventoryItem { | ||||
|             item_id: self.item_id, | ||||
|             item: | ||||
|         } | ||||
|     } | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| struct Inventory(Vec<InventoryItem>); | ||||
| 
 | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug)] | ||||
| enum InventoryError { | ||||
|     #[error("inventory full")] | ||||
|     InventoryFull, | ||||
|     #[error("stack full")] | ||||
|     StackFull, | ||||
|     #[error("meseta full")] | ||||
|     MesetaFull, | ||||
| } | ||||
| 
 | ||||
| enum AddItemResult { | ||||
|     NewItem, | ||||
|     AddToStack, | ||||
|     Meseta, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| struct LocalFloor(Vec<FloorItem>); | ||||
| #[derive(Clone)] | ||||
| struct SharedFloor(Vec<FloorItem>); | ||||
| #[derive(Clone)] | ||||
| struct RoomFloorItems(Vec<FloorItem>); | ||||
| 
 | ||||
| struct InventoryState { | ||||
|     character_id: CharacterEntityId, | ||||
|     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<AddItemResult, InventoryError> { | ||||
|         match item.item { | ||||
|             FloorItemDetail::Individual(iitem) => { | ||||
|                 if self.inventory.0.len() >= 30 { | ||||
|                     return Err(InventoryError::InventoryFull) | ||||
|                 } | ||||
|                 else { | ||||
|                     self.inventory.0.push(InventoryItem { | ||||
|                         item_id: item.item_id, | ||||
|                         item: InventoryItemDetail::Individual(iitem) | ||||
|                     }); | ||||
|                     Ok(AddItemResult::NewItem) | ||||
|                 } | ||||
|             }, | ||||
|             FloorItemDetail::Stacked(sitem) => { | ||||
|                 let existing_stack = self.inventory.0 | ||||
|                     .iter_mut() | ||||
|                     .filter_map(|item| item.item.stacked_mut()) | ||||
|                     .find(|item| { | ||||
|                         item.tool == sitem.tool | ||||
|                     }); | ||||
|                 match existing_stack { | ||||
|                     Some(existing_stack) => { | ||||
|                         if existing_stack.entity_ids.len() + sitem.entity_ids.len() > sitem.tool.max_stack() { | ||||
|                             return Err(InventoryError::StackFull) | ||||
|                         } | ||||
|                         else { | ||||
|                             existing_stack.entity_ids.append(&mut sitem.entity_ids.clone()); | ||||
|                             Ok(AddItemResult::AddToStack) | ||||
|                         } | ||||
|                     }, | ||||
|                     None => { | ||||
|                         if self.inventory.0.len() >= 30 { | ||||
|                             return Err(InventoryError::InventoryFull) | ||||
|                         } | ||||
|                         else { | ||||
|                             self.inventory.0.push(InventoryItem { | ||||
|                                 item_id: item.item_id, | ||||
|                                 item: InventoryItemDetail::Stacked(sitem) | ||||
|                             }); | ||||
|                             Ok(AddItemResult::NewItem) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 
 | ||||
|             }, | ||||
|             FloorItemDetail::Meseta(meseta) => { | ||||
|                 if self.meseta == Meseta(999999) { | ||||
|                     Err(InventoryError::MesetaFull) | ||||
|                 } | ||||
|                 else {                
 | ||||
|                     self.meseta.0 = std::cmp::min(self.meseta.0 + meseta.0 ,999999); | ||||
|                     Ok(AddItemResult::Meseta) | ||||
|                 } | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| struct FloorState { | ||||
|     character_id: CharacterEntityId, | ||||
|     local: LocalFloor, | ||||
|     shared: SharedFloor, | ||||
| } | ||||
| 
 | ||||
| impl FloorState { | ||||
|     fn take_item(&mut self, item_id: &ClientItemId) -> Option<FloorItem> { | ||||
|         let item = self.local.0 | ||||
|             .drain_filter(|item| { | ||||
|                 item.item_id == *item_id | ||||
|             }) | ||||
|             .next(); | ||||
|         item.or_else(|| { | ||||
|             self.shared.0 | ||||
|                 .drain_filter(|item| { | ||||
|                     item.item_id == *item_id | ||||
|                 }) | ||||
|                 .next() | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| struct ItemState { | ||||
|     character_inventory: HashMap<CharacterEntityId, Inventory>, | ||||
|     //character_bank: HashMap<CharacterEntityId, Bank>,
 | ||||
|     character_meseta: HashMap<CharacterEntityId, Meseta>, | ||||
|     //bank_meseta: HashMap<CharacterEntityId, Meseta>,
 | ||||
| 
 | ||||
|     character_room: HashMap<CharacterEntityId, RoomId>, | ||||
|     character_floor: HashMap<CharacterEntityId, LocalFloor>, | ||||
|     room_floor: HashMap<RoomId, SharedFloor>, | ||||
| 
 | ||||
|     //room_item_id_counter: Arc<RefCell<HashMap<RoomId, Box<dyn FnMut() -> ClientItemId + Send + Sync>>>>,
 | ||||
|     room_item_id_counter: u32, | ||||
| } | ||||
| 
 | ||||
| impl Default for ItemState { | ||||
|     fn default() -> ItemState { | ||||
|         ItemState { | ||||
|             character_inventory: HashMap::new(), | ||||
|             character_meseta: HashMap::new(), | ||||
|             character_room: HashMap::new(), | ||||
|             character_floor: HashMap::new(), | ||||
|             room_floor: HashMap::new(), | ||||
|             room_item_id_counter: 0x00810000, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* | ||||
| struct ProxiedItemState { | ||||
|     character_inventory: RefCell<HashMap<CharacterEntityId, RefCell<Inventory>>>, | ||||
|     //character_bank: HashMap<CharacterEntityId, RefCell<Bank>>,
 | ||||
|     //character_meseta: HashMap<CharacterEntityId, RefCell<Meseta>>,
 | ||||
|     //bank_meseta: HashMap<CharacterEntityId, RefCell<Meseta>>,
 | ||||
| 
 | ||||
|     character_room: RefCell<HashMap<CharacterEntityId, RefCell<RoomId>>>, | ||||
|     character_floor: RefCell<HashMap<CharacterEntityId, RefCell<RoomFloorItems>>>, | ||||
|     room_floor: RefCell<HashMap<RoomId, RefCell<RoomFloorItems>>>, | ||||
| 
 | ||||
|     //room_item_id_counter: HashMap<RoomId, RefCell<Box<dyn FnMut() -> ClientItemId + Send>>>,
 | ||||
| } | ||||
| 
 | ||||
| impl Default for ProxiedItemState { | ||||
|     fn default() -> Self { | ||||
|         ProxiedItemState { | ||||
|             character_inventory: RefCell::new(HashMap::new()), | ||||
|             //character_bank: HashMap::new(),
 | ||||
|             //character_meseta: HashMap::new(),
 | ||||
|             //bank_meseta: HashMap::new(),
 | ||||
|             character_floor: RefCell::new(HashMap::new()), | ||||
|             character_room: RefCell::new(HashMap::new()), | ||||
|             room_floor: RefCell::new(HashMap::new()), | ||||
|             //room_item_id_counter: HashMap::new(),
 | ||||
|         } | ||||
|     } | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| struct ProxiedItemState { | ||||
|     character_inventory: HashMap<CharacterEntityId, Inventory>, | ||||
|     //character_bank: HashMap<CharacterEntityId, RefCell<Bank>>,
 | ||||
|     character_meseta: HashMap<CharacterEntityId, Meseta>, | ||||
|     //bank_meseta: HashMap<CharacterEntityId, RefCell<Meseta>>,
 | ||||
| 
 | ||||
|     character_room: HashMap<CharacterEntityId, RoomId>, | ||||
|     character_floor: HashMap<CharacterEntityId, LocalFloor>, | ||||
|     room_floor: HashMap<RoomId, SharedFloor>, | ||||
| 
 | ||||
|     //room_item_id_counter: HashMap<RoomId, Box<dyn FnMut() -> ClientItemId + Send>>,
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| impl Default for ProxiedItemState { | ||||
|     fn default() -> Self { | ||||
|         ProxiedItemState { | ||||
|             character_inventory: HashMap::new(), | ||||
|             //character_bank: HashMap::new(),
 | ||||
|             character_meseta: HashMap::new(), | ||||
|             //bank_meseta: HashMap::new(),
 | ||||
|             character_floor: HashMap::new(), | ||||
|             character_room: HashMap::new(), | ||||
|             room_floor: HashMap::new(), | ||||
|             //room_item_id_counter: HashMap::new(),
 | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| struct ItemStateProxy<'a> { | ||||
|     item_state: &'a mut ItemState, | ||||
|     //entity_gateway: &'a mut dyn EntityGateway,
 | ||||
|     transaction: Box<dyn EntityGatewayTransaction>, | ||||
|     //entity_gateway: &'a mut Box<dyn EntityGateway>,
 | ||||
|     //entity_gateway: &'a mut Box<dyn EntityGateway>,
 | ||||
|     proxied_state: ProxiedItemState, | ||||
| 
 | ||||
|     gateway_actions: Vec<GatewayActions>, | ||||
| 
 | ||||
|     //_eg: std::marker::PhantomData<EG>,
 | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| fn get_or_clone<'a,  K, V>(master: &HashMap<K, V>, proxy: &'a RefCell<HashMap<K, RefCell<V>>>, key: K, err: fn(K) -> ItemStateError) -> Result<impl Deref<Target = V> + 'a, ItemStateError> | ||||
| where | ||||
|     K: Eq + std::hash::Hash + Copy, | ||||
|     V: Clone | ||||
| { | ||||
|     let existing_element = master.get(&key).ok_or_else(|| err(key))?; | ||||
|     Ok(proxy.borrow_mut().entry(key) | ||||
|         .or_insert(RefCell::new(existing_element.clone())) | ||||
|         .borrow_mut()) | ||||
| 
 | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| /* | ||||
| fn get_or_clone<'a,  K, V>(master: &HashMap<K, V>, proxy: &'a mut HashMap<K, RefCell<V>>, key: K, err: fn(K) -> ItemStateError) -> Result<impl Deref<Target = V> + 'a, ItemStateError> | ||||
| where | ||||
|     K: Eq + std::hash::Hash + Copy, | ||||
|     V: Clone | ||||
| { | ||||
|     let existing_element = master.get(&key).ok_or_else(|| err(key))?; | ||||
|     Ok(proxy.entry(key) | ||||
|         .or_insert(RefCell::new(existing_element.clone())) | ||||
|         .borrow_mut()) | ||||
| 
 | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| fn get_or_clone<K, V>(master: &HashMap<K, V>, proxy: &mut HashMap<K, V>, key: K, err: fn(K) -> ItemStateError) -> Result<V, ItemStateError> | ||||
| where | ||||
|     K: Eq + std::hash::Hash + Copy, | ||||
|     V: Clone | ||||
| { | ||||
|     let existing_element = master.get(&key).ok_or_else(|| err(key))?; | ||||
|     Ok(proxy.entry(key) | ||||
|         .or_insert(existing_element.clone()).clone()) | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 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<dyn EntityGatewayTransaction>) -> Self { | ||||
|         ItemStateProxy { | ||||
|             item_state, | ||||
|             //entity_gateway,
 | ||||
|             transaction, | ||||
|             proxied_state: Default::default(), | ||||
|             gateway_actions: Vec::new(), | ||||
|             //_eg: std::marker::PhantomData,
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn inventory(&mut self, character_id: &CharacterEntityId) -> Result<InventoryState, ItemStateError> { | ||||
|         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))?, | ||||
|             meseta: get_or_clone(&self.item_state.character_meseta, &mut self.proxied_state.character_meseta, *character_id, |c| ItemStateError::NoCharacter(c))?, | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     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<FloorState, ItemStateError> { | ||||
|         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, | ||||
|             local: get_or_clone(&self.item_state.character_floor, &mut self.proxied_state.character_floor, *character_id, |c| ItemStateError::NoCharacter(c))?, | ||||
|             shared: get_or_clone(&self.item_state.room_floor, &mut self.proxied_state.room_floor, room_id, |r| ItemStateError::NoRoom(r))?, | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     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<ClientItemId, ItemStateError> { | ||||
|         //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)) | ||||
|         /* | ||||
|         self.item_state.room_item_id_counter | ||||
|             .borrow_mut() | ||||
|             .get_mut(&room_id) | ||||
|             .ok_or(ItemStateError::NoRoom(room_id)) | ||||
|             .map(|f| f()) | ||||
|          */ | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| fn take_item_from_floor(character_id: CharacterEntityId, item_id: ClientItemId) | ||||
|                         -> impl for<'a> Fn(ItemStateProxy<'a>, ()) | ||||
|                                            -> Pin<Box<dyn Future<Output=Result<(ItemStateProxy, FloorItem), ItemStateError>> + 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<Box<dyn Future<Output=Result<(ItemStateProxy, TriggerCreateItem), ItemStateError>> + 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, | ||||
|             })) | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| //hint<R, F: FnOnce(&mut dyn EntityGateway) -> R>(f: F) -> F {f}
 | ||||
| 
 | ||||
| 
 | ||||
| #[fix_hidden_lifetime_bug] | ||||
| async fn pick_up_item<'a, EG>( | ||||
|     item_state: &'a mut ItemState, | ||||
|     //item_state: Arc<Mutex<ItemState>>,
 | ||||
|     entity_gateway: &'a mut EG, | ||||
|     character_id: &CharacterEntityId, | ||||
|     item_id: &ClientItemId) | ||||
|     -> Result<TriggerCreateItem, ItemStateError> | ||||
| where | ||||
|     'a: 'static, | ||||
|     EG: EntityGateway, | ||||
| { | ||||
|     /* | ||||
|     let transaction = entity_gateway.transaction().await.unwrap(); | ||||
| 
 | ||||
|     let item_state_proxy = ItemStateProxy::new(item_state, transaction); | ||||
|     let (mut item_state_proxy, result) = ItemStateAction::default() | ||||
|         .act(take_item_from_floor(*character_id, *item_id)) | ||||
|         .act(add_floor_item_to_inventory(*character_id)) | ||||
|         .commit(item_state_proxy) | ||||
|         .await?; | ||||
|     item_state_proxy.transaction.commit().await.unwrap(); | ||||
|      */ | ||||
| 
 | ||||
|     //drop(item_state_proxy);
 | ||||
|     //transaction.commit().await.unwrap();
 | ||||
|     //item_state_proxy.entity_gateway.commit().await.unwrap();
 | ||||
| 
 | ||||
|     let k: Result<TriggerCreateItem, ItemStateError> = entity_gateway.with_transaction(|transaction| async move { | ||||
|         let item_state_proxy = ItemStateProxy::new(item_state, transaction); | ||||
|         let (item_state_proxy, result) = ItemStateAction::default() | ||||
|             .act(take_item_from_floor(*character_id, *item_id)) | ||||
|             .act(add_floor_item_to_inventory(*character_id)) | ||||
|             .commit(item_state_proxy) | ||||
|             .await?; | ||||
| 
 | ||||
|         //let u = transaction.get_user_by_id(crate::entity::account::UserAccountId(0)).await?;
 | ||||
|         //Ok((transaction, ()))
 | ||||
|         //drop(item_state_proxy);
 | ||||
|         Ok((item_state_proxy.transaction, result)) | ||||
|     }).await; | ||||
| 
 | ||||
|     /* | ||||
|     //fn subaction(transaction: &mut dyn EntityGateway) -> Pin<Box<dyn Future<Output=Result<(), GatewayError>> + Send + 'static>> {
 | ||||
|     async fn subaction(transaction: &mut dyn EntityGateway) -> Result<(), GatewayError> { | ||||
|         let item_state_proxy = ItemStateProxy::new(item_state, transaction); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
|     
 | ||||
|     //async fn action(item_state: &mut ItemState, entity_gateway: &mut EG) -> Result<(), GatewayError> {
 | ||||
|     fn action(item_state: &mut ItemState) | ||||
|                         -> impl FnOnce(&mut dyn EntityGateway) -> Pin<Box<dyn Future<Output=Result<(), GatewayError>> + Send + 'static>> | ||||
|     { | ||||
|         /* | ||||
|         |transaction| Box::pin(async move { | ||||
|             Ok(()) | ||||
|         }) | ||||
|          */ | ||||
|         subaction | ||||
|     } | ||||
|     */ | ||||
| 
 | ||||
|     //let k: Result<(), GatewayError> = entity_gateway.with_transaction(action(item_state)).await;
 | ||||
|     
 | ||||
|     //let item_state = item_state.clone();
 | ||||
|     /* | ||||
|     let k: Result<(), GatewayError> = entity_gateway.with_transaction(|transaction| async move { | ||||
|         let item_state_proxy = ItemStateProxy::new(item_state, transaction); | ||||
|         /* | ||||
|         let item_state = item_state.clone(); | ||||
|         let mut s = item_state.lock().await; | ||||
|         //let s = s.borrow_mut();
 | ||||
|         let item_state_proxy = ItemStateProxy::new(&mut s, transaction); | ||||
|         ItemStateAction::default() | ||||
|             .act(take_item_from_floor(*character_id, *item_id)) | ||||
|             .act(add_floor_item_to_inventory(*character_id)) | ||||
|             .commit(item_state_proxy) | ||||
|             .await | ||||
|          */ | ||||
|         Ok(()) | ||||
|     }).await; | ||||
|      */ | ||||
| 
 | ||||
|     //let mut transaction = entity_gateway.transaction().await?;
 | ||||
|     
 | ||||
|     /*entity_gateway.with_transaction(|transaction| {
 | ||||
|         item_state_proxy.execute(&mut transaction)?.await | ||||
|     }).await?;*/ | ||||
| 
 | ||||
|     //Ok(result)
 | ||||
|     Ok(TriggerCreateItem::Yes) | ||||
|     //.exec_gateway(&mut entity_gateway)
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* | ||||
| fn record_item_drop(character_id: CharacterEntityId, item_drop: ItemDrop) -> impl Fn(&mut ItemStateProxy, ()) -> Result<(), ItemStateError> { | ||||
|     move |item_state, _| { | ||||
|         // how do I do this? I need EG to add_item_note but how should I kick that till later?
 | ||||
|         // general purpose vec in item_state `misc_gateway_actions`?
 | ||||
|         // can't quite use actions here as it relies on an ItemEntityId which at this point does not yet exist for the dropped item
 | ||||
|         //item_state.gateway_actions.push(GatewayAction::ItemNote(item_drop.))
 | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| /* | ||||
| fn map_drop_to_floor_item(character_id: CharacterEntityId, item_drop: ItemDrop) -> impl Fn(&mut ItemStateProxy, ()) -> Result<FloorItem, ItemStateError> { | ||||
|     move |item_state, _| { | ||||
|         match item_drop.item { | ||||
|             ItemDropType::Weapon(w) => FloorItem { | ||||
|                 item_id: item_state.new_item_id(&character_id)?, | ||||
|                 item: FloorItemDetail::Individual(item_drop.item) | ||||
|             }, | ||||
|             ItemDropType::Armor(w) => ItemOrMeseta::Individual(ItemDetail::Armor(w)), | ||||
|             ItemDropType::Shield(w) => ItemOrMeseta::Individual(ItemDetail::Shield(w)), | ||||
|             ItemDropType::Unit(w) => ItemOrMeseta::Individual(ItemDetail::Unit(w)), | ||||
|             ItemDropType::TechniqueDisk(w) => ItemOrMeseta::Individual(ItemDetail::TechniqueDisk(w)), | ||||
|             ItemDropType::Mag(w) => ItemOrMeseta::Individual(ItemDetail::Mag(w)), | ||||
|             //ItemDropType::IndividualTool(t) => ItemOrMeseta::Individual(ItemDetail::Tool(t)),
 | ||||
|             //ItemDropType::StackedTool(t, _) => ItemOrMeseta::Stacked(t),
 | ||||
|             ItemDropType::Tool(t) if t.tool.is_stackable() => ItemOrMeseta::Stacked(t), | ||||
|             ItemDropType::Tool(t) if !t.tool.is_stackable() => ItemOrMeseta::Individual(ItemDetail::Tool(t)), | ||||
|             ItemDropType::Meseta(m) => ItemOrMeseta::Meseta(Meseta(m)), | ||||
|             _ => unreachable!() // rust isnt smart enough to see that the conditional on tool catches everything
 | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| fn enemy_drops_item<EG>(item_state: &mut ItemState, | ||||
|                         entity_gateway: &mut EG, | ||||
|                         character: &CharacterEntity, | ||||
|                         item_drop: ItemDrop) | ||||
|                         -> Result<FloorItem, ItemStateError> | ||||
| where | ||||
|     EG: EntityGateway, | ||||
| { | ||||
|     ItemStateAction::default() | ||||
|         .act(record_item_drop(character.id, item_drop.clone())) | ||||
|         .act(map_drop_to_floor_item(character.id, item_drop)) | ||||
|         .act(add_item_drop_to_floor(character.id)) | ||||
|         .commit(&mut ItemStateProxy::new(item_state)) | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| /* | ||||
| fn sell_item<EG: EntityGateway>(item_state: &mut ItemState, | ||||
|                                 entity_gateway: &mut EG, | ||||
|                                 character_id: &CharacterEntityId, | ||||
|                                 item_id: &ClientItemId, | ||||
|                                 amount: usize) | ||||
|                                 -> Result<TriggerCreateItem, ItemStateError> | ||||
| where | ||||
|     EG: EntityGateway, | ||||
| { | ||||
|     ItemStateAction::default() | ||||
|         .act(take_item_from_inventory(*character_id, *item_id)) | ||||
|         .act(sell_inventory_item(*character_id, *item_id)) | ||||
|         .exec_state(&mut ItemStateProxy::new(item_state)) | ||||
|         .exec_gateway(&mut entity_gateway) | ||||
| } | ||||
| */ | ||||
| 
 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user