the start of a long process of replacing ItemManager
This commit is contained in:
		
							parent
							
								
									1f7086396e
								
							
						
					
					
						commit
						bd35481c28
					
				| @ -1,7 +1,8 @@ | ||||
| use libpso::character::character; | ||||
| use crate::common::leveltable::CharacterStats; | ||||
| use crate::entity::character::CharacterEntity; | ||||
| use crate::ship::items::{CharacterInventory, CharacterBank}; | ||||
| //use crate::ship::items::{CharacterInventory, CharacterBank};
 | ||||
| use crate::ship::items::state::{InventoryState, BankState}; | ||||
| use crate::entity::item::Meseta; | ||||
| 
 | ||||
| 
 | ||||
| @ -88,8 +89,8 @@ pub struct FullCharacterBytesBuilder<'a> { | ||||
|     stats: Option<&'a CharacterStats>, | ||||
|     level: Option<u32>, | ||||
|     meseta: Option<Meseta>, | ||||
|     inventory: Option<&'a CharacterInventory>, | ||||
|     bank: Option<&'a CharacterBank>, | ||||
|     inventory: Option<&'a InventoryState>, | ||||
|     bank: Option<&'a BankState>, | ||||
|     keyboard_config: Option<&'a [u8; 0x16C]>, | ||||
|     gamepad_config: Option<&'a [u8; 0x38]>, | ||||
|     symbol_chat: Option<&'a [u8; 1248]>, | ||||
| @ -131,7 +132,7 @@ impl<'a> FullCharacterBytesBuilder<'a> { | ||||
|     } | ||||
| 
 | ||||
|     #[must_use] | ||||
|     pub fn inventory(self, inventory: &'a CharacterInventory) -> FullCharacterBytesBuilder<'a> { | ||||
|     pub fn inventory(self, inventory: &'a InventoryState) -> FullCharacterBytesBuilder<'a> { | ||||
|         FullCharacterBytesBuilder { | ||||
|             inventory: Some(inventory), | ||||
|             ..self | ||||
| @ -139,7 +140,7 @@ impl<'a> FullCharacterBytesBuilder<'a> { | ||||
|     } | ||||
| 
 | ||||
|     #[must_use] | ||||
|     pub fn bank(self, bank: &'a CharacterBank) -> FullCharacterBytesBuilder<'a> { | ||||
|     pub fn bank(self, bank: &'a BankState) -> FullCharacterBytesBuilder<'a> { | ||||
|         FullCharacterBytesBuilder { | ||||
|             bank: Some(bank), | ||||
|             ..self | ||||
|  | ||||
| @ -388,7 +388,7 @@ impl ItemManager { | ||||
|             .map_err(|err| err.into()) | ||||
|     } | ||||
| 
 | ||||
|     pub async fn enemy_drop_item_on_local_floor<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, character: &CharacterEntity, item_drop: ItemDrop) -> Result<&FloorItem, anyhow::Error> { | ||||
|     pub async fn enemy_drop_item_on_local_floor<'a, EG: EntityGateway>(&'a mut self, entity_gateway: &'a mut EG, character: &CharacterEntity, item_drop: ItemDrop) -> Result<&'a FloorItem, anyhow::Error> { | ||||
|         let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; | ||||
| 
 | ||||
|         enum ItemOrMeseta { | ||||
| @ -550,14 +550,14 @@ impl ItemManager { | ||||
|         Ok(floor_item) | ||||
|     } | ||||
| 
 | ||||
|     pub async fn player_drops_partial_stack_on_shared_floor<EG: EntityGateway>(&mut self, | ||||
|                                                                                entity_gateway: &mut EG, | ||||
|                                                                                character: &CharacterEntity, | ||||
|                                                                                //inventory_item: InventoryItem,
 | ||||
|                                                                                item_id: ClientItemId, | ||||
|                                                                                drop_location: ItemDropLocation, | ||||
|                                                                                amount: usize) | ||||
|                                                                                -> Result<&StackedFloorItem, anyhow::Error> { | ||||
|     pub async fn player_drops_partial_stack_on_shared_floor<'a, EG: EntityGateway>(&'a mut self, | ||||
|                                                                                    entity_gateway: &'a mut EG, | ||||
|                                                                                    character: &'a CharacterEntity, | ||||
|                                                                                    //inventory_item: InventoryItem,
 | ||||
|                                                                                    item_id: ClientItemId, | ||||
|                                                                                    drop_location: ItemDropLocation, | ||||
|                                                                                    amount: usize) | ||||
|                                                                                    -> Result<&'a StackedFloorItem, anyhow::Error> { | ||||
|         let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; | ||||
|         let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; | ||||
|         let shared_floor = self.room_floor.get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?; | ||||
| @ -629,12 +629,12 @@ impl ItemManager { | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     pub async fn player_withdraws_item<EG: EntityGateway>(&mut self, | ||||
|                                                           entity_gateway: &mut EG, | ||||
|                                                           character: &CharacterEntity, | ||||
|                                                           item_id: ClientItemId, | ||||
|                                                           amount: usize) | ||||
|                                                           -> Result<&InventoryItem, anyhow::Error> { | ||||
|     pub async fn player_withdraws_item<'a, EG: EntityGateway>(&'a mut self, | ||||
|                                                               entity_gateway: &'a mut EG, | ||||
|                                                               character: &'a CharacterEntity, | ||||
|                                                               item_id: ClientItemId, | ||||
|                                                               amount: usize) | ||||
|                                                               -> Result<&'a InventoryItem, anyhow::Error> { | ||||
| 
 | ||||
|         let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; | ||||
|         let bank = self.character_bank | ||||
| @ -804,13 +804,13 @@ impl ItemManager { | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     pub async fn player_buys_item<EG: EntityGateway>(&mut self, | ||||
|                                                      entity_gateway: &mut EG, | ||||
|                                                      character: &CharacterEntity, | ||||
|                                                      shop_item: &(dyn ShopItem + Send + Sync), | ||||
|                                                      item_id: ClientItemId, | ||||
|                                                      amount: usize) | ||||
|                                                      -> Result<&InventoryItem, anyhow::Error> { | ||||
|     pub async fn player_buys_item<'a, EG: EntityGateway>(&'a mut self, | ||||
|                                                          entity_gateway: &mut EG, | ||||
|                                                          character: &'a CharacterEntity, | ||||
|                                                          shop_item: &'a (dyn ShopItem + Send + Sync), | ||||
|                                                          item_id: ClientItemId, | ||||
|                                                          amount: usize) | ||||
|                                                          -> Result<&'a InventoryItem, anyhow::Error> { | ||||
|         let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; | ||||
| 
 | ||||
|         let item_detail = shop_item.as_item(); | ||||
|  | ||||
| @ -1,13 +1,14 @@ | ||||
| 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, InventoryEntity, InventoryItemEntity}; | ||||
| use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, InventoryEntity, InventoryItemEntity, BankItemEntity, BankName, EquippedEntity}; | ||||
| use std::future::Future; | ||||
| 
 | ||||
| use crate::ship::map::MapArea; | ||||
| use crate::ship::location::RoomId; | ||||
| use crate::entity::character::CharacterEntityId; | ||||
| use crate::entity::gateway::GatewayError; | ||||
| use crate::ship::location::{AreaClient, RoomId}; | ||||
| use crate::entity::character::{CharacterEntity, CharacterEntityId}; | ||||
| use crate::entity::gateway::{EntityGateway, GatewayError}; | ||||
| use crate::entity::item::tool::Tool; | ||||
| use crate::entity::item::mag::Mag; | ||||
| use crate::ship::drops::ItemDrop; | ||||
| @ -36,6 +37,14 @@ pub enum ItemStateError { | ||||
| 
 | ||||
|     #[error("tried to drop more meseta than in inventory: {0}")] | ||||
|     InvalidMesetaDrop(u32), | ||||
| 
 | ||||
|     #[error("stacked item")] | ||||
|     StackedItemError(Vec<ItemEntity>), | ||||
| } | ||||
| 
 | ||||
| pub enum FloorType { | ||||
|     Local, | ||||
|     Shared, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -178,8 +187,8 @@ where | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct IndividualItemDetail { | ||||
|     entity_id: ItemEntityId, | ||||
|     item: ItemDetail, | ||||
|     pub entity_id: ItemEntityId, | ||||
|     pub item: ItemDetail, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| @ -188,6 +197,12 @@ pub struct StackedItemDetail { | ||||
|     pub tool: Tool, | ||||
| } | ||||
| 
 | ||||
| impl StackedItemDetail { | ||||
|     pub fn count(&self) -> usize { | ||||
|         self.entity_ids.len() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub enum InventoryItemDetail { | ||||
|     Individual(IndividualItemDetail), | ||||
| @ -207,6 +222,26 @@ impl InventoryItemDetail { | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_client_bytes(&self) -> [u8; 16] { | ||||
|         match self { | ||||
|             InventoryItemDetail::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(), | ||||
|                 } | ||||
|             }, | ||||
|             InventoryItemDetail::Stacked(item) => { | ||||
|                 item.tool.as_stacked_bytes(item.entity_ids.len()) | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -237,6 +272,41 @@ impl InventoryItem { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub enum BankItemDetail { | ||||
|     Individual(IndividualItemDetail), | ||||
|     Stacked(StackedItemDetail), | ||||
| } | ||||
| 
 | ||||
| impl BankItemDetail { | ||||
|     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 { | ||||
|     item_id: ClientItemId, | ||||
|     item: BankItemDetail, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub enum FloorItemDetail { | ||||
|     Individual(IndividualItemDetail), | ||||
| @ -327,26 +397,41 @@ pub enum InventoryError { | ||||
|     MesetaFull, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub enum AddItemResult { | ||||
|     NewItem, | ||||
|     AddToStack, | ||||
|     Meseta, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| #[derive(Clone, Default)] | ||||
| pub struct LocalFloor(Vec<FloorItem>); | ||||
| #[derive(Clone)] | ||||
| #[derive(Clone, Default)] | ||||
| pub struct SharedFloor(Vec<FloorItem>); | ||||
| #[derive(Clone)] | ||||
| pub struct RoomFloorItems(Vec<FloorItem>); | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub struct InventoryState { | ||||
|     character_id: CharacterEntityId, | ||||
|     inventory: Inventory, | ||||
|     item_id_counter: u32, | ||||
|     pub inventory: Inventory, | ||||
|     equipped: EquippedEntity, | ||||
|     pub meseta: Meseta, | ||||
| } | ||||
| 
 | ||||
| impl InventoryState { | ||||
|     pub fn initialize_item_ids(&mut self, base_item_id: u32) { | ||||
|         for (i, item) in self.inventory.0.iter_mut().enumerate() { | ||||
|             item.item_id = ClientItemId(base_item_id + i as u32); | ||||
|         } | ||||
|         self.item_id_counter = base_item_id + self.inventory.0.len() as u32 + 1; | ||||
|     } | ||||
| 
 | ||||
|     pub fn count(&self) -> usize { | ||||
|         self.inventory.0.len() | ||||
|     } | ||||
| 
 | ||||
|     pub fn add_floor_item(&mut self, item: FloorItem) -> Result<AddItemResult, InventoryError> { | ||||
|         match item.item { | ||||
|             FloorItemDetail::Individual(iitem) => { | ||||
| @ -479,6 +564,68 @@ impl InventoryState { | ||||
|         self.meseta.0 -= amount; | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_client_inventory_items(&self) -> [character::InventoryItem; 30] { | ||||
|         self.inventory.0.iter() | ||||
|             .enumerate() | ||||
|             .fold([character::InventoryItem::default(); 30], |mut inventory, (slot, item)| { | ||||
|                 let bytes = item.item.as_client_bytes(); | ||||
|                 inventory[slot].data1.copy_from_slice(&bytes[0..12]); | ||||
|                 inventory[slot].data2.copy_from_slice(&bytes[12..16]); | ||||
|                 inventory[slot].item_id = item.item_id.0; | ||||
|                 inventory[slot].equipped = 0; | ||||
|                 inventory[slot].flags = 0; | ||||
| 
 | ||||
|                 if let InventoryItemDetail::Individual(individual_item) = &item.item { | ||||
|                     if self.equipped.is_equipped(&individual_item.entity_id) { | ||||
|                         if let ItemDetail::Unit(_) = individual_item.item { | ||||
|                             inventory[slot].data1[4] = self.equipped.unit.iter() | ||||
|                                 .enumerate() | ||||
|                                 .find(|(_, u_id)| **u_id == Some(individual_item.entity_id)) | ||||
|                                 .map(|(a, _)| a) | ||||
|                                 .unwrap_or(0) as u8 | ||||
|                         } | ||||
|                         inventory[slot].equipped = 1; | ||||
|                         inventory[slot].flags |= 8; | ||||
|                     } | ||||
|                 } | ||||
|                 inventory | ||||
|             }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct Bank(Vec<BankItem>); | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct BankState { | ||||
|     character_id: CharacterEntityId, | ||||
|     item_id_counter: u32, | ||||
|     bank: Bank, | ||||
|     pub meseta: Meseta, | ||||
| } | ||||
| 
 | ||||
| impl BankState { | ||||
|     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 + 1; | ||||
|     } | ||||
| 
 | ||||
|     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 struct FloorState { | ||||
| @ -528,9 +675,9 @@ impl FloorState { | ||||
| 
 | ||||
| 
 | ||||
| pub struct ItemState { | ||||
|     character_inventory: HashMap<CharacterEntityId, Inventory>, | ||||
|     //character_bank: HashMap<CharacterEntityId, Bank>,
 | ||||
|     character_meseta: HashMap<CharacterEntityId, Meseta>, | ||||
|     character_inventory: HashMap<CharacterEntityId, InventoryState>, | ||||
|     character_bank: HashMap<CharacterEntityId, BankState>, | ||||
|     //character_meseta: HashMap<CharacterEntityId, Meseta>,
 | ||||
|     //bank_meseta: HashMap<CharacterEntityId, Meseta>,
 | ||||
| 
 | ||||
|     character_room: HashMap<CharacterEntityId, RoomId>, | ||||
| @ -545,7 +692,9 @@ impl Default for ItemState { | ||||
|     fn default() -> ItemState { | ||||
|         ItemState { | ||||
|             character_inventory: HashMap::new(), | ||||
|             character_meseta: HashMap::new(), | ||||
|             character_bank: HashMap::new(), | ||||
|             //character_meseta: HashMap::new(),
 | ||||
|             //bank_meseta: HashMap::new(),
 | ||||
|             character_room: HashMap::new(), | ||||
|             character_floor: HashMap::new(), | ||||
|             room_floor: HashMap::new(), | ||||
| @ -554,13 +703,169 @@ impl Default for ItemState { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl ItemState { | ||||
|     pub fn get_character_inventory(&self, character: &CharacterEntity) -> Result<&InventoryState, ItemStateError> { | ||||
|         Ok(self.character_inventory.get(&character.id) | ||||
|            .ok_or(ItemStateError::NoCharacter(character.id))?) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_character_bank(&self, character: &CharacterEntity) -> Result<&BankState, ItemStateError> { | ||||
|         Ok(self.character_bank.get(&character.id) | ||||
|            .ok_or(ItemStateError::NoCharacter(character.id))?) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl ItemState { | ||||
|     fn new_item_id(&mut self) -> Result<ClientItemId, ItemStateError> { | ||||
|         self.room_item_id_counter += 1; | ||||
|         Ok(ClientItemId(self.room_item_id_counter)) | ||||
|     } | ||||
| 
 | ||||
|     pub async fn load_character<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, character: &CharacterEntity) -> Result<(), ItemStateError> { | ||||
|         let inventory = entity_gateway.get_character_inventory(&character.id).await?; | ||||
|         let bank = entity_gateway.get_character_bank(&character.id, BankName("".into())).await?; | ||||
|         let equipped = entity_gateway.get_character_equips(&character.id).await?; | ||||
| 
 | ||||
|         let inventory_items = inventory.items.into_iter() | ||||
|             .map(|item| -> Result<InventoryItem, ItemStateError> { | ||||
|                 Ok(match item { | ||||
|                     InventoryItemEntity::Individual(item) => { | ||||
|                         InventoryItem { | ||||
|                             item_id: self.new_item_id()?, | ||||
|                             item: InventoryItemDetail::Individual(IndividualItemDetail { | ||||
|                                 entity_id: item.id, | ||||
|                                 item: item.item, | ||||
|                             }), | ||||
|                         } | ||||
|                     }, | ||||
|                     InventoryItemEntity::Stacked(items) => { | ||||
|                         InventoryItem { | ||||
|                             item_id: self.new_item_id()?, | ||||
|                             item: InventoryItemDetail::Stacked(StackedItemDetail { | ||||
|                                 entity_ids: items.iter().map(|i| i.id).collect(), | ||||
|                                 tool: items.get(0) | ||||
|                                     .ok_or_else(|| ItemStateError::StackedItemError(items.clone()))? | ||||
|                                     .item | ||||
|                                     .clone() | ||||
|                                     .as_tool() | ||||
|                                     .ok_or_else(|| ItemStateError::StackedItemError(items.clone()))? | ||||
|                             }) | ||||
|                         } | ||||
|                     }, | ||||
|                 }) | ||||
|             }) | ||||
|             .collect::<Result<Vec<_>, _>>()?; | ||||
| 
 | ||||
|         let character_meseta = entity_gateway.get_character_meseta(&character.id).await?; | ||||
|         let inventory_state = InventoryState { | ||||
|             character_id: character.id, | ||||
|             item_id_counter: 0, | ||||
|             inventory: Inventory(inventory_items), | ||||
|             equipped: equipped, | ||||
|             meseta: character_meseta, | ||||
|         }; | ||||
| 
 | ||||
|         let bank_items = bank.items.into_iter() | ||||
|             .map(|item| -> Result<BankItem, ItemStateError> { | ||||
|                 Ok(match item { | ||||
|                     BankItemEntity::Individual(item) => { | ||||
|                         BankItem { | ||||
|                             item_id: self.new_item_id()?, | ||||
|                             item: BankItemDetail::Individual(IndividualItemDetail { | ||||
|                                 entity_id: item.id, | ||||
|                                 item: item.item, | ||||
|                             }) | ||||
|                         } | ||||
|                     }, | ||||
|                     BankItemEntity::Stacked(items) => { | ||||
|                         BankItem { | ||||
|                             item_id: self.new_item_id()?, | ||||
|                             item:  BankItemDetail::Stacked(StackedItemDetail { | ||||
|                             entity_ids: items.iter().map(|i| i.id).collect(), | ||||
|                             tool: items.get(0) | ||||
|                                 .ok_or_else(|| ItemStateError::StackedItemError(items.clone()))? | ||||
|                                 .item | ||||
|                                 .clone() | ||||
|                                 .as_tool() | ||||
|                                 .ok_or_else(|| ItemStateError::StackedItemError(items.clone()))? | ||||
|                             }) | ||||
|                         } | ||||
|                     }, | ||||
|                 }) | ||||
|             }) | ||||
|             .collect::<Result<Vec<_>, _>>()?; | ||||
| 
 | ||||
|         let bank_meseta = entity_gateway.get_bank_meseta(&character.id, BankName("".into())).await?; | ||||
|         let bank_state = BankState { | ||||
|             character_id: character.id, | ||||
|             item_id_counter: 0, | ||||
|             bank: Bank(bank_items), | ||||
|             meseta: bank_meseta, | ||||
|         }; | ||||
| 
 | ||||
|         self.character_inventory.insert(character.id, inventory_state); | ||||
|         self.character_bank.insert(character.id, bank_state); | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn add_character_to_room(&mut self, room_id: RoomId, character: &CharacterEntity, area_client: AreaClient) { | ||||
|         let base_inventory_id = ((area_client.local_client.id() as u32) << 21) | 0x10000; | ||||
|         let inventory = self.character_inventory.get_mut(&character.id).unwrap(); | ||||
|         inventory.initialize_item_ids(base_inventory_id); | ||||
|         let base_bank_id = ((area_client.local_client.id() as u32) << 21) | 0x20000; | ||||
|         let default_bank = self.character_bank.get_mut(&character.id); | ||||
|         if let Some(default_bank ) = default_bank { | ||||
|             default_bank.initialize_item_ids(base_bank_id); | ||||
|         } | ||||
|         self.character_room.insert(character.id, room_id); | ||||
|         self.character_floor.insert(character.id, LocalFloor::default()); | ||||
|         self.room_floor.entry(room_id).or_insert_with(SharedFloor::default); | ||||
| 
 | ||||
|         /* | ||||
|         let mut inc = 0x00810000; | ||||
|         self.room_item_id_counter.borrow_mut().entry(room_id).or_insert_with(|| Box::new(move || { | ||||
|             inc += 1; | ||||
|             ClientItemId(inc) | ||||
|         })); | ||||
|          */ | ||||
|     } | ||||
| 
 | ||||
|     pub fn remove_character_from_room(&mut self, character: &CharacterEntity) { | ||||
|         self.character_inventory.remove(&character.id); | ||||
|         self.character_floor.remove(&character.id); | ||||
|         if let Some(room) = self.character_room.remove(&character.id).as_ref() { | ||||
|             if self.character_room.iter().any(|(_, r)| r == room) { | ||||
|                 self.room_floor.remove(room); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_floor_item(&self, character_id: &CharacterEntityId, item_id: &ClientItemId) -> Result<(&FloorItem, FloorType), ItemStateError> { | ||||
|         let local_floor = self.character_floor.get(character_id).ok_or(ItemStateError::NoCharacter(*character_id))?; | ||||
|         let room = self.character_room.get(character_id).ok_or(ItemStateError::NoCharacter(*character_id))?; | ||||
|         let shared_floor = self.room_floor.get(room).ok_or(ItemStateError::NoCharacter(*character_id))?; | ||||
| 
 | ||||
|         local_floor.0 | ||||
|             .iter() | ||||
|             .find(|item| item.item_id == *item_id) | ||||
|             .map(|item| (item, FloorType::Local)) | ||||
|             .or_else(|| { | ||||
|                 shared_floor.0 | ||||
|                     .iter() | ||||
|                     .find(|item| item.item_id == *item_id) | ||||
|                     .map(|item| (item, FloorType::Shared)) | ||||
|             }) | ||||
|             .ok_or_else(|| ItemStateError::NoFloorItem(*item_id)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Default)] | ||||
| 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_inventory: HashMap<CharacterEntityId, InventoryState>, | ||||
|     character_bank: HashMap<CharacterEntityId, BankState>, | ||||
|     //character_meseta: HashMap<CharacterEntityId, Meseta>,
 | ||||
|     //bank_meseta: HashMap<CharacterEntityId, Meseta>,
 | ||||
| 
 | ||||
|     character_room: HashMap<CharacterEntityId, RoomId>, | ||||
|     character_floor: HashMap<CharacterEntityId, LocalFloor>, | ||||
| @ -595,7 +900,8 @@ pub struct ItemStateProxy<'a> { | ||||
| impl<'a> ItemStateProxy<'a> { | ||||
|     pub fn commit(self) { | ||||
|         self.item_state.character_inventory.extend(self.proxied_state.character_inventory.clone()); | ||||
|         self.item_state.character_meseta.extend(self.proxied_state.character_meseta.clone()); | ||||
|         self.item_state.character_bank.extend(self.proxied_state.character_bank.clone()); | ||||
|         //self.item_state.character_meseta.extend(self.proxied_state.character_meseta.clone());
 | ||||
|         self.item_state.character_room.extend(self.proxied_state.character_room.clone()); | ||||
|         self.item_state.character_floor.extend(self.proxied_state.character_floor.clone()); | ||||
|         self.item_state.room_floor.extend(self.proxied_state.room_floor.clone()); | ||||
| @ -623,16 +929,20 @@ impl<'a> ItemStateProxy<'a> { | ||||
|     } | ||||
| 
 | ||||
|     pub fn inventory(&mut self, character_id: &CharacterEntityId) -> Result<InventoryState, ItemStateError> { | ||||
|         get_or_clone(&self.item_state.character_inventory, &mut self.proxied_state.character_inventory, *character_id, ItemStateError::NoCharacter) | ||||
|         /* | ||||
|         Ok(InventoryState { | ||||
|             character_id: *character_id, | ||||
|             inventory: get_or_clone(&self.item_state.character_inventory, &mut self.proxied_state.character_inventory, *character_id, ItemStateError::NoCharacter)?, | ||||
|             meseta: get_or_clone(&self.item_state.character_meseta, &mut self.proxied_state.character_meseta, *character_id, ItemStateError::NoCharacter)?, | ||||
|         }) | ||||
|          */ | ||||
|     } | ||||
| 
 | ||||
|     pub fn set_inventory(&mut self, inventory: InventoryState) { | ||||
|         self.proxied_state.character_inventory.insert(inventory.character_id, inventory.inventory); | ||||
|         self.proxied_state.character_meseta.insert(inventory.character_id, inventory.meseta); | ||||
|         self.proxied_state.character_inventory.insert(inventory.character_id, inventory); | ||||
|         //self.proxied_state.character_inventory.insert(inventory.character_id, inventory.inventory);
 | ||||
|         //self.proxied_state.character_meseta.insert(inventory.character_id, inventory.meseta);
 | ||||
|     } | ||||
| 
 | ||||
|     pub fn floor(&mut self, character_id: &CharacterEntityId) -> Result<FloorState, ItemStateError> { | ||||
| @ -651,7 +961,6 @@ impl<'a> ItemStateProxy<'a> { | ||||
|     } | ||||
| 
 | ||||
|     pub fn new_item_id(&mut self) -> Result<ClientItemId, ItemStateError> { | ||||
|         self.item_state.room_item_id_counter += 1; | ||||
|         Ok(ClientItemId(self.item_state.room_item_id_counter)) | ||||
|         self.item_state.new_item_id() | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -78,15 +78,15 @@ pub fn create_withdrawn_inventory_item(area_client: AreaClient, item: &Inventory | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
| pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem) -> Result<RemoveItemFromFloor, ShipError> { | ||||
| pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem2) -> Result<RemoveItemFromFloor, ShipError> { | ||||
|     Ok(RemoveItemFromFloor { | ||||
|         client: area_client.local_client.id(), | ||||
|         target: 0, | ||||
|         client_id: area_client.local_client.id(), | ||||
|         unknown: 0, | ||||
|         map_area: item.map_area().area_value(), | ||||
|         map_area: item.map_area.area_value(), | ||||
|         unknown2: 0, | ||||
|         item_id: item.item_id().0, | ||||
|         item_id: item.item_id.0, | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -8,12 +8,14 @@ use crate::common::serverstate::ClientId; | ||||
| use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms, ItemShops}; | ||||
| use crate::ship::location::{ClientLocation, ClientLocationError}; | ||||
| use crate::ship::drops::ItemDrop; | ||||
| use crate::ship::items::{ItemManager, ItemManagerError, ClientItemId, TriggerCreateItem, FloorItem, FloorType}; | ||||
| use crate::ship::items::{ItemManager, ItemManagerError, ClientItemId, FloorItem}; | ||||
| use crate::entity::gateway::EntityGateway; | ||||
| use crate::entity::item; | ||||
| use libpso::utf8_to_utf16_array; | ||||
| use crate::ship::packet::builder; | ||||
| use crate::ship::shops::{ShopItem, ToolShopItem, ArmorShopItem}; | ||||
| use crate::ship::items::state::{ItemState, FloorType, FloorItemDetail}; | ||||
| use crate::ship::items::actions::{pick_up_item, TriggerCreateItem}; | ||||
| 
 | ||||
| const BANK_ACTION_DEPOSIT: u8 = 0; | ||||
| const BANK_ACTION_WITHDRAW: u8 = 1; | ||||
| @ -123,7 +125,7 @@ pub async fn pickup_item<EG>(id: ClientId, | ||||
|                              entity_gateway: &mut EG, | ||||
|                              client_location: &ClientLocation, | ||||
|                              clients: &mut Clients, | ||||
|                              item_manager: &mut ItemManager) | ||||
|                              item_state: &mut ItemState) | ||||
|                              -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error> | ||||
| where | ||||
|     EG: EntityGateway | ||||
| @ -134,7 +136,9 @@ where | ||||
|     let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; | ||||
| 
 | ||||
|     // TODO: should not need to fetch the item here to construct this packet
 | ||||
|     let (item, floor_type) = item_manager.get_floor_item_by_id(&client.character, ClientItemId(pickup_item.item_id))?; | ||||
|     //let (item, floor_type) = item_manager.get_floor_item_by_id(&client.character, ClientItemId(pickup_item.item_id))?;
 | ||||
|     /* | ||||
|     let (item, floor_type) = item_state.get_floor_item(&client.character, &ClientItemId(pickup_item.item_id))?; | ||||
|     let remove_item = builder::message::remove_item_from_floor(area_client, item)?; | ||||
|     let create_item = match item { | ||||
|         FloorItem::Individual(individual_floor_item) => Some(builder::message::create_individual_item(area_client, item.item_id(), &individual_floor_item.item)?), | ||||
| @ -142,8 +146,19 @@ where | ||||
|         FloorItem::Meseta(_) => None, | ||||
|         //_ => Some(builder::message::create_item(area_client, &item)?),
 | ||||
|     }; | ||||
|      */ | ||||
| 
 | ||||
|     match item_manager.character_picks_up_item(entity_gateway, &mut client.character, ClientItemId(pickup_item.item_id)).await { | ||||
|     let (item, floor_type) = item_state.get_floor_item(&client.character.id, &ClientItemId(pickup_item.item_id))?; | ||||
|     let remove_item = builder::message::remove_item_from_floor(area_client, item)?; | ||||
|     let create_item = match &item.item { | ||||
|         FloorItemDetail::Individual(individual_floor_item) => Some(builder::message::create_individual_item(area_client, item.item_id, &individual_floor_item.item)?), | ||||
|         FloorItemDetail::Stacked(stacked_floor_item) => Some(builder::message::create_stacked_item(area_client, item.item_id, &stacked_floor_item.tool, stacked_floor_item.count())?), | ||||
|         FloorItemDetail::Meseta(_) => None, | ||||
|         //_ => Some(builder::message::create_item(area_client, &item)?),
 | ||||
|     }; | ||||
| 
 | ||||
|     //match item_manager.character_picks_up_item(entity_gateway, &mut client.character, ClientItemId(pickup_item.item_id)).await {
 | ||||
|     match pick_up_item(item_state, entity_gateway, &mut client.character, &ClientItemId(pickup_item.item_id)).await { | ||||
|         Ok(trigger_create_item) => { | ||||
|             let remove_packets: Box<dyn Iterator<Item=(ClientId, SendShipPacket)> + Send> = match floor_type { | ||||
|                 FloorType::Local => { | ||||
|  | ||||
| @ -5,6 +5,7 @@ use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms}; | ||||
| use crate::ship::character::{FullCharacterBytesBuilder}; | ||||
| use crate::ship::location::{ClientLocation, LobbyId, RoomLobby, ClientLocationError, RoomId}; | ||||
| use crate::ship::packet; | ||||
| use crate::ship::items::state::ItemState; | ||||
| use crate::ship::items::ItemManager; | ||||
| use crate::entity::gateway::EntityGateway; | ||||
| use crate::ship::map::MapArea; | ||||
| @ -13,7 +14,7 @@ use crate::ship::map::MapArea; | ||||
| pub fn block_selected(id: ClientId, | ||||
|                       pkt: &MenuSelect, | ||||
|                       clients: &mut Clients, | ||||
|                       item_manager: &ItemManager, | ||||
|                       item_state: &ItemState, | ||||
|                       level_table: &CharacterLevelTable) | ||||
|                       -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> { | ||||
|     let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; | ||||
| @ -21,15 +22,14 @@ pub fn block_selected(id: ClientId, | ||||
| 
 | ||||
|     let (level, stats) = level_table.get_stats_from_exp(client.character.char_class, client.character.exp); | ||||
| 
 | ||||
|     let inventory = item_manager.get_character_inventory(&client.character).unwrap(); | ||||
|     let meseta = item_manager.get_character_meseta(&client.character.id).unwrap(); | ||||
|     let bank = item_manager.get_character_bank(&client.character).unwrap(); | ||||
|     let inventory = item_state.get_character_inventory(&client.character).unwrap(); | ||||
|     let bank = item_state.get_character_bank(&client.character).unwrap(); | ||||
| 
 | ||||
|     let fc = FullCharacterBytesBuilder::default() | ||||
|         .character(&client.character) | ||||
|         .stats(&stats) | ||||
|         .level(level) | ||||
|         .meseta(*meseta) | ||||
|         .meseta(inventory.meseta) | ||||
|         .inventory(inventory) | ||||
|         .bank(bank) | ||||
|         .keyboard_config(&client.character.keyboard_config.as_bytes()) | ||||
|  | ||||
| @ -547,7 +547,7 @@ impl<EG: EntityGateway> ShipServerState<EG> { | ||||
|                 handler::direct_message::request_item(id, request_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_manager).await? | ||||
|             }, | ||||
|             GameMessage::PickupItem(pickup_item) => { | ||||
|                 handler::direct_message::pickup_item(id, pickup_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_manager).await? | ||||
|                 handler::direct_message::pickup_item(id, pickup_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? | ||||
|             }, | ||||
|             GameMessage::BoxDropRequest(box_drop_request) => { | ||||
|                 handler::direct_message::request_box_item(id, box_drop_request, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_manager).await? | ||||
| @ -629,7 +629,7 @@ impl<EG: EntityGateway> ServerState for ShipServerState<EG> { | ||||
|                     } | ||||
|                     BLOCK_MENU_ID => { | ||||
|                         let leave_lobby = handler::lobby::remove_from_lobby(id, &mut block.client_location).into_iter().into_iter().flatten(); | ||||
|                         let select_block = handler::lobby::block_selected(id, menuselect, &mut self.clients, &self.item_manager, &self.level_table)?.into_iter(); | ||||
|                         let select_block = handler::lobby::block_selected(id, menuselect, &mut self.clients, &self.item_state, &self.level_table)?.into_iter(); | ||||
|                         Box::new(leave_lobby.chain(select_block)) | ||||
|                     } | ||||
|                     ROOM_MENU_ID => handler::room::join_room(id, menuselect, &mut block.client_location, &mut self.clients, &mut self.item_manager, &self.level_table, &mut block.rooms)?, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user