use crate::ship::items::ClientItemId; use libpso::character::character;//::InventoryItem; use crate::entity::item::{ItemEntityId, ItemEntity, ItemDetail, ItemLocation, BankEntity, BankItemEntity, BankName}; use crate::entity::character::CharacterEntityId; use crate::entity::item::tool::Tool; use crate::ship::items::inventory::{InventoryItemHandle, InventoryItem}; const BANK_CAPACITY: usize = 200; #[derive(Debug, Clone)] pub struct IndividualBankItem { pub entity_id: ItemEntityId, pub item_id: ClientItemId, pub item: ItemDetail, } #[derive(Debug, Clone)] pub struct StackedBankItem { pub entity_ids: Vec, pub item_id: ClientItemId, pub tool: Tool, } impl StackedBankItem { pub fn count(&self) -> usize { self.entity_ids.len() } pub fn take_entity_ids(&mut self, amount: usize) -> Option> { if amount <= self.count() { Some(self.entity_ids.drain(..amount).collect()) } else { None } } } #[derive(Debug, Clone)] pub enum BankItem { Individual(IndividualBankItem), Stacked(StackedBankItem), } 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.as_client_bytes()[0..4]); other_bytes.copy_from_slice(&other.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 { //let self_bytes = self.as_client_bytes(); //let other_bytes = other.as_client_bytes(); let mut self_bytes = [0u8; 4]; let mut other_bytes = [0u8; 4]; self_bytes.copy_from_slice(&self.as_client_bytes()[0..4]); other_bytes.copy_from_slice(&other.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 self_bytes = self.as_client_bytes(); //let other_bytes = other.as_client_bytes(); let mut self_bytes = [0u8; 4]; let mut other_bytes = [0u8; 4]; self_bytes.copy_from_slice(&self.as_client_bytes()[0..4]); other_bytes.copy_from_slice(&other.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) } } impl BankItem { pub fn set_item_id(&mut self, item_id: ClientItemId) { match self { BankItem::Individual(individual_bank_item) => { individual_bank_item.item_id = item_id }, BankItem::Stacked(stacked_bank_item) => { stacked_bank_item.item_id = item_id } } } pub fn item_id(&self) -> ClientItemId { match self { BankItem::Individual(individual_bank_item) => { individual_bank_item.item_id }, BankItem::Stacked(stacked_bank_item) => { stacked_bank_item.item_id } } } pub fn as_client_bytes(&self) -> [u8; 16] { match self { BankItem::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(), } }, BankItem::Stacked(item) => { item.tool.as_stacked_bytes(item.entity_ids.len()) }, } } } pub struct BankItemHandle<'a> { bank: &'a mut CharacterBank, index: usize } impl<'a> BankItemHandle<'a> { pub fn item(&'a self) -> Option<&'a BankItem> { self.bank.items.get(self.index) } pub fn item_mut(&mut self) -> Option<&mut BankItem> { self.bank.items.get_mut(self.index) } pub fn remove_from_bank(self) { self.bank.items.remove(self.index); } } pub struct CharacterBank { item_id_counter: u32, items: Vec } impl CharacterBank { pub fn new(mut items: Vec) -> CharacterBank { items.sort(); CharacterBank { item_id_counter: 0, items: items, } } pub fn initialize_item_ids(&mut self, base_item_id: u32) { for (i, item) in self.items.iter_mut().enumerate() { item.set_item_id(ClientItemId(base_item_id + i as u32)); } self.item_id_counter = base_item_id + self.items.len() as u32 + 1; } pub fn get_item_handle_by_id<'a>(&'a mut self, item_id: ClientItemId) -> Option> { let (index, _) = self.items.iter() .enumerate() .filter(|(_, item)| { item.item_id() == item_id }) .nth(0)?; Some(BankItemHandle { bank: self, index: index, }) } pub fn as_client_bank_items(&self) -> character::Bank { self.items.iter() .enumerate() .fold(character::Bank::default(), |mut bank, (slot, item)| { bank.item_count = (slot + 1) as u32; let bytes = 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 { self.items.iter() .map(|item| { let bytes = 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 { BankItem::Individual(_individual_bank_item) => { 1 }, BankItem::Stacked(stacked_bank_item) => { stacked_bank_item.count() }, }; character::BankItem { data1: data1, data2: data2, item_id: item.item_id().0, amount: amount as u16, flags: 1, } }) .collect() } pub fn count(&self) -> usize { self.items.len() } pub fn deposit_item(&mut self, mut inventory_item: InventoryItemHandle, amount: usize) -> Option<&BankItem> { let remove = match inventory_item.item_mut()? { InventoryItem::Individual(individual_inventory_item) => { if self.items.len() >= BANK_CAPACITY { return None } self.items.push(BankItem::Individual(IndividualBankItem { entity_id: individual_inventory_item.entity_id, item_id: individual_inventory_item.item_id, item: individual_inventory_item.item.clone(), })); true }, InventoryItem::Stacked(stacked_inventory_item) => { let existing_bank_item = self.items.iter_mut() .find_map(|item| { if let BankItem::Stacked(stacked_bank_item) = item { if stacked_bank_item.tool == stacked_inventory_item.tool { return Some(stacked_bank_item) } } None }); match existing_bank_item { Some(stacked_bank_item) => { if stacked_bank_item.count() + stacked_inventory_item.count() > stacked_inventory_item.tool.max_stack() { return None } let mut deposited_entity_ids = stacked_inventory_item.take_entity_ids(amount)?; stacked_bank_item.entity_ids.append(&mut deposited_entity_ids); } None => { if self.items.len() >= BANK_CAPACITY { return None } let deposited_entity_ids = stacked_inventory_item.take_entity_ids(amount)?; self.item_id_counter += 1; self.items.push(BankItem::Stacked(StackedBankItem { entity_ids: deposited_entity_ids, item_id: ClientItemId(self.item_id_counter), tool: stacked_inventory_item.tool, })) } } stacked_inventory_item.count() == 0 } }; if remove { inventory_item.remove_from_inventory(); } self.items.last() } pub fn as_bank_entity(&self, character_id: &CharacterEntityId, bank_name: &BankName) -> BankEntity { BankEntity { items: self.items.iter() .map(|item| { match item { BankItem::Individual(item) => { BankItemEntity::Individual(ItemEntity { id: item.entity_id, location: ItemLocation::Bank { character_id: *character_id, name: bank_name.clone(), }, item: item.item.clone(), }) }, BankItem::Stacked(items) => { BankItemEntity::Stacked(items.entity_ids.iter() .map(|id| { ItemEntity { id: *id, location: ItemLocation::Bank { character_id: *character_id, name: bank_name.clone(), }, item: ItemDetail::Tool(items.tool) } }) .collect()) }, } }) .collect() } } }