move bank code out of state
This commit is contained in:
		
							parent
							
								
									414b3d2ce5
								
							
						
					
					
						commit
						24639496da
					
				| @ -2,7 +2,7 @@ use libpso::character::character; | ||||
| use crate::common::leveltable::CharacterStats; | ||||
| use crate::entity::character::CharacterEntity; | ||||
| //use crate::ship::items::{CharacterInventory, CharacterBank};
 | ||||
| use crate::ship::items::state::{BankState}; | ||||
| use crate::ship::items::bank::BankState; | ||||
| use crate::ship::items::inventory::InventoryState; | ||||
| use crate::entity::item::Meseta; | ||||
| 
 | ||||
|  | ||||
| @ -8,7 +8,8 @@ use std::pin::Pin; | ||||
| use crate::ship::map::MapArea; | ||||
| use crate::entity::character::{CharacterEntity, CharacterEntityId}; | ||||
| use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction}; | ||||
| use crate::ship::items::state::{ItemState, ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, BankItem, BankItemDetail, IndividualItemDetail}; | ||||
| use crate::ship::items::state::{ItemState, ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, IndividualItemDetail}; | ||||
| use crate::ship::items::bank::{BankItem, BankItemDetail}; | ||||
| use crate::ship::items::itemstateaction::{ItemStateAction, ItemAction}; | ||||
| use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail}; | ||||
| use crate::ship::items::floor::{FloorItem, FloorItemDetail}; | ||||
|  | ||||
							
								
								
									
										340
									
								
								src/ship/items/bank.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										340
									
								
								src/ship/items/bank.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,340 @@ | ||||
| use std::cmp::Ordering; | ||||
| use libpso::character::character; | ||||
| use crate::ship::items::ClientItemId; | ||||
| use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, BankEntity, BankItemEntity, BankName}; | ||||
| use std::future::Future; | ||||
| 
 | ||||
| use crate::entity::character::CharacterEntityId; | ||||
| use crate::ship::items::state::ItemStateError; | ||||
| use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail, AddItemResult}; | ||||
| use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail}; | ||||
| 
 | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug)] | ||||
| pub enum BankError { | ||||
|     #[error("bank full")] | ||||
|     BankFull, | ||||
|     #[error("stack full")] | ||||
|     StackFull, | ||||
|     #[error("meseta full")] | ||||
|     MesetaFull, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub enum BankItemDetail { | ||||
|     Individual(IndividualItemDetail), | ||||
|     Stacked(StackedItemDetail), | ||||
| } | ||||
| 
 | ||||
| impl BankItemDetail { | ||||
|     fn stacked_mut(&mut self) -> Option<&mut StackedItemDetail> { | ||||
|         match self { | ||||
|             BankItemDetail::Stacked(sitem) => Some(sitem), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_client_bytes(&self) -> [u8; 16] { | ||||
|         match self { | ||||
|             BankItemDetail::Individual(item) => { | ||||
|                 match &item.item { | ||||
|                     ItemDetail::Weapon(w) => w.as_bytes(), | ||||
|                     ItemDetail::Armor(a) => a.as_bytes(), | ||||
|                     ItemDetail::Shield(s) => s.as_bytes(), | ||||
|                     ItemDetail::Unit(u) => u.as_bytes(), | ||||
|                     ItemDetail::Tool(t) => t.as_individual_bytes(), | ||||
|                     ItemDetail::TechniqueDisk(d) => d.as_bytes(), | ||||
|                     ItemDetail::Mag(m) => m.as_bytes(), | ||||
|                     ItemDetail::ESWeapon(e) => e.as_bytes(), | ||||
|                 } | ||||
|             }, | ||||
|             BankItemDetail::Stacked(item) => { | ||||
|                 item.tool.as_stacked_bytes(item.entity_ids.len()) | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct BankItem { | ||||
|     pub item_id: ClientItemId, | ||||
|     pub item: BankItemDetail, | ||||
| } | ||||
| 
 | ||||
| impl BankItem { | ||||
|     pub async fn with_entity_id<F, Fut, T>(&self, mut param: T, mut func: F) -> Result<T, ItemStateError> | ||||
|     where | ||||
|         F: FnMut(T, ItemEntityId) -> Fut, | ||||
|         Fut: Future<Output=Result<T, ItemStateError>>, | ||||
|     { | ||||
|         match &self.item { | ||||
|             BankItemDetail::Individual(individual_item) => { | ||||
|                 param = func(param, individual_item.entity_id).await?; | ||||
|             }, | ||||
|             BankItemDetail::Stacked(stacked_item) => { | ||||
|                 for entity_id in &stacked_item.entity_ids { | ||||
|                     param = func(param, *entity_id).await?; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         Ok(param) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct Bank(Vec<BankItem>); | ||||
| 
 | ||||
| impl Bank { | ||||
|     pub fn new(items: Vec<BankItem>) -> Bank { | ||||
|         Bank(items) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct BankState { | ||||
|     pub character_id: CharacterEntityId, | ||||
|     pub item_id_counter: u32, | ||||
|     pub name: BankName, | ||||
|     pub bank: Bank, | ||||
|     pub meseta: Meseta, | ||||
| } | ||||
| 
 | ||||
| impl BankState { | ||||
|     pub fn new(character_id: CharacterEntityId, name: BankName, mut bank: Bank, meseta: Meseta) -> BankState { | ||||
|         bank.0.sort(); | ||||
|         BankState { | ||||
|             character_id, | ||||
|             item_id_counter: 0, | ||||
|             name, | ||||
|             bank, | ||||
|             meseta, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn count(&self) -> usize { | ||||
|         self.bank.0.len() | ||||
|     } | ||||
| 
 | ||||
|     pub fn initialize_item_ids(&mut self, base_item_id: u32) { | ||||
|         for (i, item) in self.bank.0.iter_mut().enumerate() { | ||||
|             item.item_id = ClientItemId(base_item_id + i as u32); | ||||
|         } | ||||
|         self.item_id_counter = base_item_id + self.bank.0.len() as u32; | ||||
|     } | ||||
| 
 | ||||
|     pub fn add_meseta(&mut self, amount: u32) -> Result<(), ItemStateError> { | ||||
|         if self.meseta.0 + amount > 999999 { | ||||
|             return Err(ItemStateError::FullOfMeseta) | ||||
|         } | ||||
|         self.meseta.0 += amount; | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn remove_meseta(&mut self, amount: u32) -> Result<(), ItemStateError> { | ||||
|         if amount > self.meseta.0 { | ||||
|             return Err(ItemStateError::InvalidMesetaRemoval(amount)) | ||||
|         } | ||||
|         self.meseta.0 -= amount; | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn add_inventory_item(&mut self, item: InventoryItem) -> Result<AddItemResult, BankError> { | ||||
|         match item.item { | ||||
|             InventoryItemDetail::Individual(iitem) => { | ||||
|                 if self.bank.0.len() >= 30 { | ||||
|                     Err(BankError::BankFull) | ||||
|                 } | ||||
|                 else { | ||||
|                     self.bank.0.push(BankItem { | ||||
|                         item_id: item.item_id, | ||||
|                         item: BankItemDetail::Individual(iitem) | ||||
|                     }); | ||||
|                     self.bank.0.sort(); | ||||
|                     Ok(AddItemResult::NewItem) | ||||
|                 } | ||||
|             }, | ||||
|             InventoryItemDetail::Stacked(sitem) => { | ||||
|                 let existing_stack = self.bank.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() { | ||||
|                             Err(BankError::StackFull) | ||||
|                         } | ||||
|                         else { | ||||
|                             existing_stack.entity_ids.append(&mut sitem.entity_ids.clone()); | ||||
|                             Ok(AddItemResult::AddToStack) | ||||
|                         } | ||||
|                     }, | ||||
|                     None => { | ||||
|                         if self.bank.0.len() >= 30 { | ||||
|                             Err(BankError::BankFull) | ||||
|                         } | ||||
|                         else { | ||||
|                             self.bank.0.push(BankItem { | ||||
|                                 item_id: item.item_id, | ||||
|                                 item: BankItemDetail::Stacked(sitem) | ||||
|                             }); | ||||
|                             self.bank.0.sort(); | ||||
|                             Ok(AddItemResult::NewItem) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn take_item(&mut self, item_id: &ClientItemId, amount: u32) -> Option<BankItem> { | ||||
|         let idx = self.bank.0 | ||||
|             .iter() | ||||
|             .position(|i| i.item_id == *item_id)?; | ||||
|         match &mut self.bank.0[idx].item { | ||||
|             BankItemDetail::Individual(_individual_item) => { | ||||
|                 Some(self.bank.0.remove(idx)) | ||||
|             }, | ||||
|             BankItemDetail::Stacked(stacked_item) => { | ||||
|                 let remove_all = match stacked_item.entity_ids.len().cmp(&(amount as usize)) { | ||||
|                     Ordering::Equal => true, | ||||
|                     Ordering::Greater => false, | ||||
|                     Ordering::Less => return None, | ||||
|                 }; | ||||
| 
 | ||||
|                 if remove_all { | ||||
|                     Some(self.bank.0.remove(idx)) | ||||
|                 } | ||||
|                 else { | ||||
|                     let entity_ids = stacked_item.entity_ids.drain(..(amount as usize)).collect(); | ||||
|                     self.item_id_counter += 1; | ||||
|                     Some(BankItem { | ||||
|                         item_id: ClientItemId(self.item_id_counter), | ||||
|                         item: BankItemDetail::Stacked(StackedItemDetail { | ||||
|                             entity_ids, | ||||
|                             tool: stacked_item.tool, | ||||
|                         })}) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_client_bank_items(&self) -> character::Bank { | ||||
|         self.bank.0.iter() | ||||
|             .enumerate() | ||||
|             .fold(character::Bank::default(), |mut bank, (slot, item)| { | ||||
|                 bank.item_count = (slot + 1) as u32; | ||||
|                 let bytes = item.item.as_client_bytes(); | ||||
|                 bank.items[slot].data1.copy_from_slice(&bytes[0..12]); | ||||
|                 bank.items[slot].data2.copy_from_slice(&bytes[12..16]); | ||||
|                 bank.items[slot].item_id = item.item_id.0; | ||||
| 
 | ||||
|                 bank | ||||
|             }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_client_bank_request(&self) -> Vec<character::BankItem> { | ||||
|         self.bank.0.iter() | ||||
|             .map(|item| { | ||||
|                 let bytes = item.item.as_client_bytes(); | ||||
|                 let mut data1 = [0; 12]; | ||||
|                 let mut data2 = [0; 4]; | ||||
|                 data1.copy_from_slice(&bytes[0..12]); | ||||
|                 data2.copy_from_slice(&bytes[12..16]); | ||||
|                 let amount = match &item.item { | ||||
|                     BankItemDetail::Individual(_individual_bank_item) => { | ||||
|                         1 | ||||
|                     }, | ||||
|                     BankItemDetail::Stacked(stacked_bank_item) => { | ||||
|                         stacked_bank_item.count() | ||||
|                     }, | ||||
|                 }; | ||||
|                 character::BankItem { | ||||
|                     data1, | ||||
|                     data2, | ||||
|                     item_id: item.item_id.0, | ||||
|                     amount: amount as u16, | ||||
|                     flags: 1, | ||||
|                 } | ||||
|             }) | ||||
|             .collect() | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_bank_entity(&self) -> BankEntity { | ||||
|         BankEntity { | ||||
|             items: self.bank.0.iter() | ||||
|                 .map(|item| { | ||||
|                     match &item.item { | ||||
|                         BankItemDetail::Individual(item) => { | ||||
|                             BankItemEntity::Individual(ItemEntity { | ||||
|                                 id: item.entity_id, | ||||
|                                 item: item.item.clone(), | ||||
|                             }) | ||||
|                         }, | ||||
|                         BankItemDetail::Stacked(items) => { | ||||
|                             BankItemEntity::Stacked(items.entity_ids.iter() | ||||
|                                                     .map(|id| { | ||||
|                                                         ItemEntity { | ||||
|                                                             id: *id, | ||||
|                                                             item: ItemDetail::Tool(items.tool) | ||||
|                                                         } | ||||
|                                                     }) | ||||
|                                                     .collect()) | ||||
|                         }, | ||||
|                     } | ||||
|                 }) | ||||
|                 .collect() | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl std::cmp::PartialEq for BankItem { | ||||
|     fn eq(&self, other: &BankItem) -> bool { | ||||
|         let mut self_bytes = [0u8; 4]; | ||||
|         let mut other_bytes = [0u8; 4]; | ||||
|         self_bytes.copy_from_slice(&self.item.as_client_bytes()[0..4]); | ||||
|         other_bytes.copy_from_slice(&other.item.as_client_bytes()[0..4]); | ||||
| 
 | ||||
|         let self_value = u32::from_be_bytes(self_bytes); | ||||
|         let other_value = u32::from_be_bytes(other_bytes); | ||||
| 
 | ||||
|         self_value.eq(&other_value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl std::cmp::Eq for BankItem {} | ||||
| 
 | ||||
| impl std::cmp::PartialOrd for BankItem { | ||||
|     fn partial_cmp(&self, other: &BankItem) -> Option<std::cmp::Ordering> { | ||||
|         let mut self_bytes = [0u8; 4]; | ||||
|         let mut other_bytes = [0u8; 4]; | ||||
|         self_bytes.copy_from_slice(&self.item.as_client_bytes()[0..4]); | ||||
|         other_bytes.copy_from_slice(&other.item.as_client_bytes()[0..4]); | ||||
| 
 | ||||
| 
 | ||||
|         let self_value = u32::from_be_bytes(self_bytes); | ||||
|         let other_value = u32::from_be_bytes(other_bytes); | ||||
| 
 | ||||
|         self_value.partial_cmp(&other_value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl std::cmp::Ord for BankItem { | ||||
|     fn cmp(&self, other: &BankItem) -> std::cmp::Ordering { | ||||
|         let mut self_bytes = [0u8; 4]; | ||||
|         let mut other_bytes = [0u8; 4]; | ||||
|         self_bytes.copy_from_slice(&self.item.as_client_bytes()[0..4]); | ||||
|         other_bytes.copy_from_slice(&other.item.as_client_bytes()[0..4]); | ||||
| 
 | ||||
| 
 | ||||
|         let self_value = u32::from_le_bytes(self_bytes); | ||||
|         let other_value = u32::from_le_bytes(other_bytes); | ||||
| 
 | ||||
|         self_value.cmp(&other_value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -4,6 +4,7 @@ pub mod apply_item; | ||||
| pub mod itemstateaction; | ||||
| pub mod inventory; | ||||
| pub mod floor; | ||||
| pub mod bank; | ||||
| 
 | ||||
| #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize, derive_more::Display)] | ||||
| pub struct ClientItemId(pub u32); | ||||
|  | ||||
| @ -1,9 +1,6 @@ | ||||
| use std::cmp::Ordering; | ||||
| use std::collections::HashMap; | ||||
| use libpso::character::character; | ||||
| use crate::ship::items::ClientItemId; | ||||
| use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, InventoryItemEntity, BankEntity, BankItemEntity, BankName}; | ||||
| use std::future::Future; | ||||
| use crate::entity::item::{ItemEntityId, ItemDetail, ItemEntity, InventoryItemEntity, BankItemEntity, BankName}; | ||||
| 
 | ||||
| use crate::ship::location::{AreaClient, RoomId}; | ||||
| use crate::entity::character::{CharacterEntity, CharacterEntityId}; | ||||
| @ -14,8 +11,8 @@ use crate::entity::item::mag::Mag; | ||||
| use crate::ship::drops::ItemDrop; | ||||
| 
 | ||||
| use crate::ship::items::inventory::{Inventory, InventoryItem, InventoryItemDetail, InventoryError, InventoryState}; | ||||
| 
 | ||||
| use crate::ship::items::floor::{FloorState, FloorItem, LocalFloor, SharedFloor, FloorType}; | ||||
| use crate::ship::items::bank::{Bank, BankState, BankItem, BankItemDetail, BankError}; | ||||
| 
 | ||||
| // TODO: Commit trait that ItemStateProxy and EntityTransaction implement that .commit requires and acts on upon everything succeeding (like 3 less lines of code!)
 | ||||
| 
 | ||||
| @ -136,78 +133,7 @@ impl StackedItemDetail { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub enum BankItemDetail { | ||||
|     Individual(IndividualItemDetail), | ||||
|     Stacked(StackedItemDetail), | ||||
| } | ||||
| 
 | ||||
| impl BankItemDetail { | ||||
|     fn stacked_mut(&mut self) -> Option<&mut StackedItemDetail> { | ||||
|         match self { | ||||
|             BankItemDetail::Stacked(sitem) => Some(sitem), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_client_bytes(&self) -> [u8; 16] { | ||||
|         match self { | ||||
|             BankItemDetail::Individual(item) => { | ||||
|                 match &item.item { | ||||
|                     ItemDetail::Weapon(w) => w.as_bytes(), | ||||
|                     ItemDetail::Armor(a) => a.as_bytes(), | ||||
|                     ItemDetail::Shield(s) => s.as_bytes(), | ||||
|                     ItemDetail::Unit(u) => u.as_bytes(), | ||||
|                     ItemDetail::Tool(t) => t.as_individual_bytes(), | ||||
|                     ItemDetail::TechniqueDisk(d) => d.as_bytes(), | ||||
|                     ItemDetail::Mag(m) => m.as_bytes(), | ||||
|                     ItemDetail::ESWeapon(e) => e.as_bytes(), | ||||
|                 } | ||||
|             }, | ||||
|             BankItemDetail::Stacked(item) => { | ||||
|                 item.tool.as_stacked_bytes(item.entity_ids.len()) | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct BankItem { | ||||
|     pub item_id: ClientItemId, | ||||
|     pub item: BankItemDetail, | ||||
| } | ||||
| 
 | ||||
| impl BankItem { | ||||
|     pub async fn with_entity_id<F, Fut, T>(&self, mut param: T, mut func: F) -> Result<T, ItemStateError> | ||||
|     where | ||||
|         F: FnMut(T, ItemEntityId) -> Fut, | ||||
|         Fut: Future<Output=Result<T, ItemStateError>>, | ||||
|     { | ||||
|         match &self.item { | ||||
|             BankItemDetail::Individual(individual_item) => { | ||||
|                 param = func(param, individual_item.entity_id).await?; | ||||
|             }, | ||||
|             BankItemDetail::Stacked(stacked_item) => { | ||||
|                 for entity_id in &stacked_item.entity_ids { | ||||
|                     param = func(param, *entity_id).await?; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         Ok(param) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug)] | ||||
| pub enum BankError { | ||||
|     #[error("bank full")] | ||||
|     BankFull, | ||||
|     #[error("stack full")] | ||||
|     StackFull, | ||||
|     #[error("meseta full")] | ||||
|     MesetaFull, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub enum AddItemResult { | ||||
| @ -216,254 +142,6 @@ pub enum AddItemResult { | ||||
|     Meseta, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct Bank(Vec<BankItem>); | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct BankState { | ||||
|     character_id: CharacterEntityId, | ||||
|     item_id_counter: u32, | ||||
|     pub name: BankName, | ||||
|     bank: Bank, | ||||
|     pub meseta: Meseta, | ||||
| } | ||||
| 
 | ||||
| impl BankState { | ||||
|     pub fn new(character_id: CharacterEntityId, name: BankName, mut bank: Bank, meseta: Meseta) -> BankState { | ||||
|         bank.0.sort(); | ||||
|         BankState { | ||||
|             character_id, | ||||
|             item_id_counter: 0, | ||||
|             name, | ||||
|             bank, | ||||
|             meseta, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn count(&self) -> usize { | ||||
|         self.bank.0.len() | ||||
|     } | ||||
| 
 | ||||
|     pub fn initialize_item_ids(&mut self, base_item_id: u32) { | ||||
|         for (i, item) in self.bank.0.iter_mut().enumerate() { | ||||
|             item.item_id = ClientItemId(base_item_id + i as u32); | ||||
|         } | ||||
|         self.item_id_counter = base_item_id + self.bank.0.len() as u32; | ||||
|     } | ||||
| 
 | ||||
|     pub fn add_meseta(&mut self, amount: u32) -> Result<(), ItemStateError> { | ||||
|         if self.meseta.0 + amount > 999999 { | ||||
|             return Err(ItemStateError::FullOfMeseta) | ||||
|         } | ||||
|         self.meseta.0 += amount; | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn remove_meseta(&mut self, amount: u32) -> Result<(), ItemStateError> { | ||||
|         if amount > self.meseta.0 { | ||||
|             return Err(ItemStateError::InvalidMesetaRemoval(amount)) | ||||
|         } | ||||
|         self.meseta.0 -= amount; | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn add_inventory_item(&mut self, item: InventoryItem) -> Result<AddItemResult, BankError> { | ||||
|         match item.item { | ||||
|             InventoryItemDetail::Individual(iitem) => { | ||||
|                 if self.bank.0.len() >= 30 { | ||||
|                     Err(BankError::BankFull) | ||||
|                 } | ||||
|                 else { | ||||
|                     self.bank.0.push(BankItem { | ||||
|                         item_id: item.item_id, | ||||
|                         item: BankItemDetail::Individual(iitem) | ||||
|                     }); | ||||
|                     self.bank.0.sort(); | ||||
|                     Ok(AddItemResult::NewItem) | ||||
|                 } | ||||
|             }, | ||||
|             InventoryItemDetail::Stacked(sitem) => { | ||||
|                 let existing_stack = self.bank.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() { | ||||
|                             Err(BankError::StackFull) | ||||
|                         } | ||||
|                         else { | ||||
|                             existing_stack.entity_ids.append(&mut sitem.entity_ids.clone()); | ||||
|                             Ok(AddItemResult::AddToStack) | ||||
|                         } | ||||
|                     }, | ||||
|                     None => { | ||||
|                         if self.bank.0.len() >= 30 { | ||||
|                             Err(BankError::BankFull) | ||||
|                         } | ||||
|                         else { | ||||
|                             self.bank.0.push(BankItem { | ||||
|                                 item_id: item.item_id, | ||||
|                                 item: BankItemDetail::Stacked(sitem) | ||||
|                             }); | ||||
|                             self.bank.0.sort(); | ||||
|                             Ok(AddItemResult::NewItem) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn take_item(&mut self, item_id: &ClientItemId, amount: u32) -> Option<BankItem> { | ||||
|         let idx = self.bank.0 | ||||
|             .iter() | ||||
|             .position(|i| i.item_id == *item_id)?; | ||||
|         match &mut self.bank.0[idx].item { | ||||
|             BankItemDetail::Individual(_individual_item) => { | ||||
|                 Some(self.bank.0.remove(idx)) | ||||
|             }, | ||||
|             BankItemDetail::Stacked(stacked_item) => { | ||||
|                 let remove_all = match stacked_item.entity_ids.len().cmp(&(amount as usize)) { | ||||
|                     Ordering::Equal => true, | ||||
|                     Ordering::Greater => false, | ||||
|                     Ordering::Less => return None, | ||||
|                 }; | ||||
| 
 | ||||
|                 if remove_all { | ||||
|                     Some(self.bank.0.remove(idx)) | ||||
|                 } | ||||
|                 else { | ||||
|                     let entity_ids = stacked_item.entity_ids.drain(..(amount as usize)).collect(); | ||||
|                     self.item_id_counter += 1; | ||||
|                     Some(BankItem { | ||||
|                         item_id: ClientItemId(self.item_id_counter), | ||||
|                         item: BankItemDetail::Stacked(StackedItemDetail { | ||||
|                             entity_ids, | ||||
|                             tool: stacked_item.tool, | ||||
|                         })}) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_client_bank_items(&self) -> character::Bank { | ||||
|         self.bank.0.iter() | ||||
|             .enumerate() | ||||
|             .fold(character::Bank::default(), |mut bank, (slot, item)| { | ||||
|                 bank.item_count = (slot + 1) as u32; | ||||
|                 let bytes = item.item.as_client_bytes(); | ||||
|                 bank.items[slot].data1.copy_from_slice(&bytes[0..12]); | ||||
|                 bank.items[slot].data2.copy_from_slice(&bytes[12..16]); | ||||
|                 bank.items[slot].item_id = item.item_id.0; | ||||
| 
 | ||||
|                 bank | ||||
|             }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_client_bank_request(&self) -> Vec<character::BankItem> { | ||||
|         self.bank.0.iter() | ||||
|             .map(|item| { | ||||
|                 let bytes = item.item.as_client_bytes(); | ||||
|                 let mut data1 = [0; 12]; | ||||
|                 let mut data2 = [0; 4]; | ||||
|                 data1.copy_from_slice(&bytes[0..12]); | ||||
|                 data2.copy_from_slice(&bytes[12..16]); | ||||
|                 let amount = match &item.item { | ||||
|                     BankItemDetail::Individual(_individual_bank_item) => { | ||||
|                         1 | ||||
|                     }, | ||||
|                     BankItemDetail::Stacked(stacked_bank_item) => { | ||||
|                         stacked_bank_item.count() | ||||
|                     }, | ||||
|                 }; | ||||
|                 character::BankItem { | ||||
|                     data1, | ||||
|                     data2, | ||||
|                     item_id: item.item_id.0, | ||||
|                     amount: amount as u16, | ||||
|                     flags: 1, | ||||
|                 } | ||||
|             }) | ||||
|             .collect() | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_bank_entity(&self) -> BankEntity { | ||||
|         BankEntity { | ||||
|             items: self.bank.0.iter() | ||||
|                 .map(|item| { | ||||
|                     match &item.item { | ||||
|                         BankItemDetail::Individual(item) => { | ||||
|                             BankItemEntity::Individual(ItemEntity { | ||||
|                                 id: item.entity_id, | ||||
|                                 item: item.item.clone(), | ||||
|                             }) | ||||
|                         }, | ||||
|                         BankItemDetail::Stacked(items) => { | ||||
|                             BankItemEntity::Stacked(items.entity_ids.iter() | ||||
|                                                     .map(|id| { | ||||
|                                                         ItemEntity { | ||||
|                                                             id: *id, | ||||
|                                                             item: ItemDetail::Tool(items.tool) | ||||
|                                                         } | ||||
|                                                     }) | ||||
|                                                     .collect()) | ||||
|                         }, | ||||
|                     } | ||||
|                 }) | ||||
|                 .collect() | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl std::cmp::PartialEq for BankItem { | ||||
|     fn eq(&self, other: &BankItem) -> bool { | ||||
|         let mut self_bytes = [0u8; 4]; | ||||
|         let mut other_bytes = [0u8; 4]; | ||||
|         self_bytes.copy_from_slice(&self.item.as_client_bytes()[0..4]); | ||||
|         other_bytes.copy_from_slice(&other.item.as_client_bytes()[0..4]); | ||||
| 
 | ||||
|         let self_value = u32::from_be_bytes(self_bytes); | ||||
|         let other_value = u32::from_be_bytes(other_bytes); | ||||
| 
 | ||||
|         self_value.eq(&other_value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl std::cmp::Eq for BankItem {} | ||||
| 
 | ||||
| impl std::cmp::PartialOrd for BankItem { | ||||
|     fn partial_cmp(&self, other: &BankItem) -> Option<std::cmp::Ordering> { | ||||
|         let mut self_bytes = [0u8; 4]; | ||||
|         let mut other_bytes = [0u8; 4]; | ||||
|         self_bytes.copy_from_slice(&self.item.as_client_bytes()[0..4]); | ||||
|         other_bytes.copy_from_slice(&other.item.as_client_bytes()[0..4]); | ||||
| 
 | ||||
| 
 | ||||
|         let self_value = u32::from_be_bytes(self_bytes); | ||||
|         let other_value = u32::from_be_bytes(other_bytes); | ||||
| 
 | ||||
|         self_value.partial_cmp(&other_value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl std::cmp::Ord for BankItem { | ||||
|     fn cmp(&self, other: &BankItem) -> std::cmp::Ordering { | ||||
|         let mut self_bytes = [0u8; 4]; | ||||
|         let mut other_bytes = [0u8; 4]; | ||||
|         self_bytes.copy_from_slice(&self.item.as_client_bytes()[0..4]); | ||||
|         other_bytes.copy_from_slice(&other.item.as_client_bytes()[0..4]); | ||||
| 
 | ||||
| 
 | ||||
|         let self_value = u32::from_le_bytes(self_bytes); | ||||
|         let other_value = u32::from_le_bytes(other_bytes); | ||||
| 
 | ||||
|         self_value.cmp(&other_value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| pub struct ItemState { | ||||
|     character_inventory: HashMap<CharacterEntityId, InventoryState>, | ||||
| @ -582,7 +260,7 @@ impl ItemState { | ||||
|             .collect::<Result<Vec<_>, _>>()?; | ||||
| 
 | ||||
|         let bank_meseta = entity_gateway.get_bank_meseta(&character.id, &BankName("".into())).await?; | ||||
|         let bank_state = BankState::new(character.id, BankName("".into()), Bank(bank_items), bank_meseta); | ||||
|         let bank_state = BankState::new(character.id, BankName("".into()), Bank::new(bank_items), bank_meseta); | ||||
| 
 | ||||
|         self.character_inventory.insert(character.id, inventory_state); | ||||
|         self.character_bank.insert(character.id, bank_state); | ||||
|  | ||||
| @ -6,7 +6,7 @@ use crate::ship::ship::{ShipError}; | ||||
| use crate::ship::items::ClientItemId; | ||||
| use crate::ship::items::inventory::InventoryItem; | ||||
| use crate::ship::items::state::IndividualItemDetail; | ||||
| use crate::ship::items::state::BankState; | ||||
| use crate::ship::items::bank::BankState; | ||||
| use crate::ship::items::floor::FloorItem; | ||||
| use crate::ship::location::AreaClient; | ||||
| use std::convert::TryInto; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user