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 = "0.19.5" | ||||||
| strum_macros = "0.19" | strum_macros = "0.19" | ||||||
| anyhow = { version = "1.0.47", features = ["backtrace"] } | anyhow = { version = "1.0.47", features = ["backtrace"] } | ||||||
| 
 | fix-hidden-lifetime-bug = "0.2.4" | ||||||
|  | |||||||
| @ -3,6 +3,8 @@ | |||||||
| #![feature(drain_filter)] | #![feature(drain_filter)] | ||||||
| #![feature(try_blocks)] | #![feature(try_blocks)] | ||||||
| 
 | 
 | ||||||
|  | #[macro_use] | ||||||
|  | extern crate fix_hidden_lifetime_bug; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| pub mod common; | pub mod common; | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ pub mod inventory; | |||||||
| pub mod manager; | pub mod manager; | ||||||
| pub mod transaction; | pub mod transaction; | ||||||
| pub mod use_tool; | pub mod use_tool; | ||||||
|  | pub mod state; | ||||||
| use serde::{Serialize, Deserialize}; | use serde::{Serialize, Deserialize}; | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, derive_more::Display)] | #[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