the start of a long process of replacing ItemManager
This commit is contained in:
parent
85912f07db
commit
35ab24c390
@ -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 => {
|
||||
|
@ -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<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())
|
||||
|
@ -545,7 +545,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?
|
||||
@ -627,7 +627,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