Browse Source

the start of a long process of replacing ItemManager

pull/112/head
jake 3 years ago
committed by andy
parent
commit
bd35481c28
  1. 11
      src/ship/character.rs
  2. 26
      src/ship/items/manager.rs
  3. 353
      src/ship/items/state.rs
  4. 6
      src/ship/packet/builder/message.rs
  5. 23
      src/ship/packet/handler/direct_message.rs
  6. 10
      src/ship/packet/handler/lobby.rs
  7. 4
      src/ship/ship.rs

11
src/ship/character.rs

@ -1,7 +1,8 @@
use libpso::character::character; use libpso::character::character;
use crate::common::leveltable::CharacterStats; use crate::common::leveltable::CharacterStats;
use crate::entity::character::CharacterEntity; 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; use crate::entity::item::Meseta;
@ -88,8 +89,8 @@ pub struct FullCharacterBytesBuilder<'a> {
stats: Option<&'a CharacterStats>, stats: Option<&'a CharacterStats>,
level: Option<u32>, level: Option<u32>,
meseta: Option<Meseta>, 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]>, keyboard_config: Option<&'a [u8; 0x16C]>,
gamepad_config: Option<&'a [u8; 0x38]>, gamepad_config: Option<&'a [u8; 0x38]>,
symbol_chat: Option<&'a [u8; 1248]>, symbol_chat: Option<&'a [u8; 1248]>,
@ -131,7 +132,7 @@ impl<'a> FullCharacterBytesBuilder<'a> {
} }
#[must_use] #[must_use]
pub fn inventory(self, inventory: &'a CharacterInventory) -> FullCharacterBytesBuilder<'a> {
pub fn inventory(self, inventory: &'a InventoryState) -> FullCharacterBytesBuilder<'a> {
FullCharacterBytesBuilder { FullCharacterBytesBuilder {
inventory: Some(inventory), inventory: Some(inventory),
..self ..self
@ -139,7 +140,7 @@ impl<'a> FullCharacterBytesBuilder<'a> {
} }
#[must_use] #[must_use]
pub fn bank(self, bank: &'a CharacterBank) -> FullCharacterBytesBuilder<'a> {
pub fn bank(self, bank: &'a BankState) -> FullCharacterBytesBuilder<'a> {
FullCharacterBytesBuilder { FullCharacterBytesBuilder {
bank: Some(bank), bank: Some(bank),
..self ..self

26
src/ship/items/manager.rs

@ -388,7 +388,7 @@ impl ItemManager {
.map_err(|err| err.into()) .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))?; let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
enum ItemOrMeseta { enum ItemOrMeseta {
@ -550,14 +550,14 @@ impl ItemManager {
Ok(floor_item) Ok(floor_item)
} }
pub async fn player_drops_partial_stack_on_shared_floor<EG: EntityGateway>(&mut self,
entity_gateway: &mut EG,
character: &CharacterEntity,
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, //inventory_item: InventoryItem,
item_id: ClientItemId, item_id: ClientItemId,
drop_location: ItemDropLocation, drop_location: ItemDropLocation,
amount: usize) amount: usize)
-> Result<&StackedFloorItem, anyhow::Error> {
-> Result<&'a StackedFloorItem, anyhow::Error> {
let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; 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 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))?; let shared_floor = self.room_floor.get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?;
@ -629,12 +629,12 @@ impl ItemManager {
Ok(()) Ok(())
} }
pub async fn player_withdraws_item<EG: EntityGateway>(&mut self,
entity_gateway: &mut EG,
character: &CharacterEntity,
pub async fn player_withdraws_item<'a, EG: EntityGateway>(&'a mut self,
entity_gateway: &'a mut EG,
character: &'a CharacterEntity,
item_id: ClientItemId, item_id: ClientItemId,
amount: usize) amount: usize)
-> Result<&InventoryItem, anyhow::Error> {
-> Result<&'a InventoryItem, anyhow::Error> {
let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
let bank = self.character_bank let bank = self.character_bank
@ -804,13 +804,13 @@ impl ItemManager {
Ok(()) Ok(())
} }
pub async fn player_buys_item<EG: EntityGateway>(&mut self,
pub async fn player_buys_item<'a, EG: EntityGateway>(&'a mut self,
entity_gateway: &mut EG, entity_gateway: &mut EG,
character: &CharacterEntity,
shop_item: &(dyn ShopItem + Send + Sync),
character: &'a CharacterEntity,
shop_item: &'a (dyn ShopItem + Send + Sync),
item_id: ClientItemId, item_id: ClientItemId,
amount: usize) amount: usize)
-> Result<&InventoryItem, anyhow::Error> {
-> Result<&'a InventoryItem, anyhow::Error> {
let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
let item_detail = shop_item.as_item(); let item_detail = shop_item.as_item();

353
src/ship/items/state.rs

@ -1,13 +1,14 @@
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::HashMap; use std::collections::HashMap;
use libpso::character::character;
use crate::ship::items::ClientItemId; 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 std::future::Future;
use crate::ship::map::MapArea; 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::tool::Tool;
use crate::entity::item::mag::Mag; use crate::entity::item::mag::Mag;
use crate::ship::drops::ItemDrop; use crate::ship::drops::ItemDrop;
@ -36,6 +37,14 @@ pub enum ItemStateError {
#[error("tried to drop more meseta than in inventory: {0}")] #[error("tried to drop more meseta than in inventory: {0}")]
InvalidMesetaDrop(u32), InvalidMesetaDrop(u32),
#[error("stacked item")]
StackedItemError(Vec<ItemEntity>),
}
pub enum FloorType {
Local,
Shared,
} }
@ -178,8 +187,8 @@ where
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct IndividualItemDetail { pub struct IndividualItemDetail {
entity_id: ItemEntityId,
item: ItemDetail,
pub entity_id: ItemEntityId,
pub item: ItemDetail,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -188,6 +197,12 @@ pub struct StackedItemDetail {
pub tool: Tool, pub tool: Tool,
} }
impl StackedItemDetail {
pub fn count(&self) -> usize {
self.entity_ids.len()
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum InventoryItemDetail { pub enum InventoryItemDetail {
Individual(IndividualItemDetail), Individual(IndividualItemDetail),
@ -207,6 +222,26 @@ impl InventoryItemDetail {
_ => None, _ => 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)] #[derive(Clone)]
pub enum FloorItemDetail { pub enum FloorItemDetail {
Individual(IndividualItemDetail), Individual(IndividualItemDetail),
@ -327,26 +397,41 @@ pub enum InventoryError {
MesetaFull, MesetaFull,
} }
#[derive(Clone)]
pub enum AddItemResult { pub enum AddItemResult {
NewItem, NewItem,
AddToStack, AddToStack,
Meseta, Meseta,
} }
#[derive(Clone)]
#[derive(Clone, Default)]
pub struct LocalFloor(Vec<FloorItem>); pub struct LocalFloor(Vec<FloorItem>);
#[derive(Clone)]
#[derive(Clone, Default)]
pub struct SharedFloor(Vec<FloorItem>); pub struct SharedFloor(Vec<FloorItem>);
#[derive(Clone)] #[derive(Clone)]
pub struct RoomFloorItems(Vec<FloorItem>); pub struct RoomFloorItems(Vec<FloorItem>);
#[derive(Clone)]
pub struct InventoryState { pub struct InventoryState {
character_id: CharacterEntityId, character_id: CharacterEntityId,
inventory: Inventory,
item_id_counter: u32,
pub inventory: Inventory,
equipped: EquippedEntity,
pub meseta: Meseta, pub meseta: Meseta,
} }
impl InventoryState { 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> { pub fn add_floor_item(&mut self, item: FloorItem) -> Result<AddItemResult, InventoryError> {
match item.item { match item.item {
FloorItemDetail::Individual(iitem) => { FloorItemDetail::Individual(iitem) => {
@ -479,6 +564,68 @@ impl InventoryState {
self.meseta.0 -= amount; self.meseta.0 -= amount;
Ok(()) 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 { pub struct FloorState {
@ -528,9 +675,9 @@ impl FloorState {
pub struct ItemState { 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>, //bank_meseta: HashMap<CharacterEntityId, Meseta>,
character_room: HashMap<CharacterEntityId, RoomId>, character_room: HashMap<CharacterEntityId, RoomId>,
@ -545,7 +692,9 @@ impl Default for ItemState {
fn default() -> ItemState { fn default() -> ItemState {
ItemState { ItemState {
character_inventory: HashMap::new(), 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_room: HashMap::new(),
character_floor: HashMap::new(), character_floor: HashMap::new(),
room_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)] #[derive(Default)]
struct ProxiedItemState { 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_room: HashMap<CharacterEntityId, RoomId>,
character_floor: HashMap<CharacterEntityId, LocalFloor>, character_floor: HashMap<CharacterEntityId, LocalFloor>,
@ -595,7 +900,8 @@ pub struct ItemStateProxy<'a> {
impl<'a> ItemStateProxy<'a> { impl<'a> ItemStateProxy<'a> {
pub fn commit(self) { pub fn commit(self) {
self.item_state.character_inventory.extend(self.proxied_state.character_inventory.clone()); 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_room.extend(self.proxied_state.character_room.clone());
self.item_state.character_floor.extend(self.proxied_state.character_floor.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()); 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> { 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 { Ok(InventoryState {
character_id: *character_id, character_id: *character_id,
inventory: get_or_clone(&self.item_state.character_inventory, &mut self.proxied_state.character_inventory, *character_id, ItemStateError::NoCharacter)?, 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)?, 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) { 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> { 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> { 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()
} }
} }

6
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<RemoveItemFromFloor, ShipError> {
pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem2) -> Result<RemoveItemFromFloor, ShipError> {
Ok(RemoveItemFromFloor { Ok(RemoveItemFromFloor {
client: area_client.local_client.id(), client: area_client.local_client.id(),
target: 0, target: 0,
client_id: area_client.local_client.id(), client_id: area_client.local_client.id(),
unknown: 0, unknown: 0,
map_area: item.map_area().area_value(),
map_area: item.map_area.area_value(),
unknown2: 0, unknown2: 0,
item_id: item.item_id().0,
item_id: item.item_id.0,
}) })
} }

23
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::ship::{SendShipPacket, ShipError, Clients, Rooms, ItemShops};
use crate::ship::location::{ClientLocation, ClientLocationError}; use crate::ship::location::{ClientLocation, ClientLocationError};
use crate::ship::drops::ItemDrop; 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::gateway::EntityGateway;
use crate::entity::item; use crate::entity::item;
use libpso::utf8_to_utf16_array; use libpso::utf8_to_utf16_array;
use crate::ship::packet::builder; use crate::ship::packet::builder;
use crate::ship::shops::{ShopItem, ToolShopItem, ArmorShopItem}; 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_DEPOSIT: u8 = 0;
const BANK_ACTION_WITHDRAW: u8 = 1; const BANK_ACTION_WITHDRAW: u8 = 1;
@ -123,7 +125,7 @@ pub async fn pickup_item<EG>(id: ClientId,
entity_gateway: &mut EG, entity_gateway: &mut EG,
client_location: &ClientLocation, client_location: &ClientLocation,
clients: &mut Clients, clients: &mut Clients,
item_manager: &mut ItemManager)
item_state: &mut ItemState)
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error> -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error>
where where
EG: EntityGateway 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() })?; 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 // 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 remove_item = builder::message::remove_item_from_floor(area_client, item)?;
let create_item = match 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)?), 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, FloorItem::Meseta(_) => None,
//_ => Some(builder::message::create_item(area_client, &item)?), //_ => Some(builder::message::create_item(area_client, &item)?),
}; };
*/
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 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) => { Ok(trigger_create_item) => {
let remove_packets: Box<dyn Iterator<Item=(ClientId, SendShipPacket)> + Send> = match floor_type { let remove_packets: Box<dyn Iterator<Item=(ClientId, SendShipPacket)> + Send> = match floor_type {
FloorType::Local => { FloorType::Local => {

10
src/ship/packet/handler/lobby.rs

@ -5,6 +5,7 @@ use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms};
use crate::ship::character::{FullCharacterBytesBuilder}; use crate::ship::character::{FullCharacterBytesBuilder};
use crate::ship::location::{ClientLocation, LobbyId, RoomLobby, ClientLocationError, RoomId}; use crate::ship::location::{ClientLocation, LobbyId, RoomLobby, ClientLocationError, RoomId};
use crate::ship::packet; use crate::ship::packet;
use crate::ship::items::state::ItemState;
use crate::ship::items::ItemManager; use crate::ship::items::ItemManager;
use crate::entity::gateway::EntityGateway; use crate::entity::gateway::EntityGateway;
use crate::ship::map::MapArea; use crate::ship::map::MapArea;
@ -13,7 +14,7 @@ use crate::ship::map::MapArea;
pub fn block_selected(id: ClientId, pub fn block_selected(id: ClientId,
pkt: &MenuSelect, pkt: &MenuSelect,
clients: &mut Clients, clients: &mut Clients,
item_manager: &ItemManager,
item_state: &ItemState,
level_table: &CharacterLevelTable) level_table: &CharacterLevelTable)
-> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> { -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> {
let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; 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 (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() let fc = FullCharacterBytesBuilder::default()
.character(&client.character) .character(&client.character)
.stats(&stats) .stats(&stats)
.level(level) .level(level)
.meseta(*meseta)
.meseta(inventory.meseta)
.inventory(inventory) .inventory(inventory)
.bank(bank) .bank(bank)
.keyboard_config(&client.character.keyboard_config.as_bytes()) .keyboard_config(&client.character.keyboard_config.as_bytes())

4
src/ship/ship.rs

@ -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? 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) => { 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) => { 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? 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 => { BLOCK_MENU_ID => {
let leave_lobby = handler::lobby::remove_from_lobby(id, &mut block.client_location).into_iter().into_iter().flatten(); 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)) 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)?, 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…
Cancel
Save