diff --git a/src/ship/character.rs b/src/ship/character.rs index 39064aa..d2144cd 100644 --- a/src/ship/character.rs +++ b/src/ship/character.rs @@ -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, meseta: Option, - 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 diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index 1d492b4..1cd7d83 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -393,7 +393,7 @@ impl ItemManager { .map_err(|err| err.into()) } - pub async fn enemy_drop_item_on_local_floor(&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 { @@ -555,14 +555,14 @@ impl ItemManager { Ok(floor_item) } - pub async fn player_drops_partial_stack_on_shared_floor(&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))?; @@ -634,12 +634,12 @@ impl ItemManager { Ok(()) } - pub async fn player_withdraws_item(&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 @@ -808,13 +808,13 @@ impl ItemManager { Ok(()) } - pub async fn player_buys_item(&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(); diff --git a/src/ship/items/state.rs b/src/ship/items/state.rs index ac07759..a92bc4b 100644 --- a/src/ship/items/state.rs +++ b/src/ship/items/state.rs @@ -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), +} + +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); -#[derive(Clone)] +#[derive(Clone, Default)] pub struct SharedFloor(Vec); #[derive(Clone)] pub struct RoomFloorItems(Vec); +#[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 { 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); + +#[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, - //character_bank: HashMap, - character_meseta: HashMap, + character_inventory: HashMap, + character_bank: HashMap, + //character_meseta: HashMap, //bank_meseta: HashMap, character_room: HashMap, @@ -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 { + self.room_item_id_counter += 1; + Ok(ClientItemId(self.room_item_id_counter)) + } + + pub async fn load_character(&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 { + 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::, _>>()?; + + 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 { + 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::, _>>()?; + + 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, - //character_bank: HashMap>, - character_meseta: HashMap, - //bank_meseta: HashMap>, + character_inventory: HashMap, + character_bank: HashMap, + //character_meseta: HashMap, + //bank_meseta: HashMap, character_room: HashMap, character_floor: HashMap, @@ -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 { + 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 { @@ -651,7 +961,6 @@ impl<'a> ItemStateProxy<'a> { } pub fn new_item_id(&mut self) -> Result { - self.item_state.room_item_id_counter += 1; - Ok(ClientItemId(self.item_state.room_item_id_counter)) + self.item_state.new_item_id() } } diff --git a/src/ship/packet/builder/message.rs b/src/ship/packet/builder/message.rs index 23f3ea1..a5303bc 100644 --- a/src/ship/packet/builder/message.rs +++ b/src/ship/packet/builder/message.rs @@ -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 { +pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem2) -> Result { 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, }) } diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index 03206d1..69e09e7 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -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; @@ -129,7 +131,7 @@ pub async fn pickup_item(id: ClientId, entity_gateway: &mut EG, client_location: &ClientLocation, clients: &mut Clients, - item_manager: &mut ItemManager) + item_state: &mut ItemState) -> Result + Send>, anyhow::Error> where EG: EntityGateway @@ -140,7 +142,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)?), @@ -148,8 +152,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 + Send> = match floor_type { FloorType::Local => { diff --git a/src/ship/packet/handler/lobby.rs b/src/ship/packet/handler/lobby.rs index 37f18da..d7670a4 100644 --- a/src/ship/packet/handler/lobby.rs +++ b/src/ship/packet/handler/lobby.rs @@ -6,6 +6,7 @@ use crate::ship::character::{FullCharacterBytesBuilder}; use crate::ship::location::{ClientLocation, LobbyId, RoomLobby, ClientLocationError}; //use crate::ship::items::; use crate::ship::packet; +use crate::ship::items::state::ItemState; use crate::ship::items::ItemManager; use crate::entity::gateway::EntityGateway; @@ -13,7 +14,7 @@ use crate::entity::gateway::EntityGateway; pub fn block_selected(id: ClientId, pkt: &MenuSelect, clients: &mut Clients, - item_manager: &ItemManager, + item_state: &ItemState, level_table: &CharacterLevelTable) -> Result, 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()) diff --git a/src/ship/ship.rs b/src/ship/ship.rs index f34d3b9..4d73a87 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -549,7 +549,7 @@ impl ShipServerState { 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? @@ -631,7 +631,7 @@ impl ServerState for ShipServerState { } 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)?,