remove old item manager code
This commit is contained in:
		
							parent
							
								
									d1d48cae3b
								
							
						
					
					
						commit
						098b1a79e7
					
				
							
								
								
									
										12
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										12
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -172,6 +172,17 @@ dependencies = [ | ||||
|  "winapi", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "async-recursion" | ||||
| version = "1.0.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "2cda8f4bcc10624c4e85bc66b3f452cca98cfa5ca002dc83a16aad2367641bea" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "async-std" | ||||
| version = "1.11.0" | ||||
| @ -587,6 +598,7 @@ version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "ages-prs", | ||||
|  "anyhow", | ||||
|  "async-recursion", | ||||
|  "async-std", | ||||
|  "async-trait", | ||||
|  "barrel", | ||||
|  | ||||
| @ -11,7 +11,6 @@ use crate::ship::items::state::{ItemState, ItemStateProxy, ItemStateAction, Item | ||||
| use crate::ship::items::apply_item::apply_item; | ||||
| use crate::entity::item::{ItemDetail, NewItemEntity, TradeId}; | ||||
| use crate::entity::item::tool::Tool; | ||||
| use crate::entity::item::weapon::WeaponModifier; | ||||
| use crate::entity::item::ItemModifier; | ||||
| use crate::ship::shops::ShopItem; | ||||
| use crate::ship::trade::TradeItem; | ||||
|  | ||||
| @ -1,12 +1,11 @@ | ||||
| use thiserror::Error; | ||||
| use std::convert::TryFrom; | ||||
| use std::convert::TryInto; | ||||
| use crate::entity::gateway::{EntityGateway, GatewayError}; | ||||
| use crate::entity::character::CharacterEntity; | ||||
| use crate::entity::item::mag::{MagCell, MagCellError}; | ||||
| use crate::entity::item::tool::ToolType; | ||||
| use crate::entity::item::{ItemDetail, ItemEntityId}; | ||||
| use crate::ship::items::state::{ItemStateProxy, InventoryState, InventoryItem, InventoryItemDetail, ItemStateError}; | ||||
| use crate::ship::items::state::{ItemStateProxy, InventoryItem, InventoryItemDetail, ItemStateError}; | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Error, Debug)] | ||||
|  | ||||
| @ -1,324 +0,0 @@ | ||||
| use crate::ship::items::ClientItemId; | ||||
| use libpso::character::character;//::InventoryItem;
 | ||||
| use crate::entity::item::{ItemEntityId, ItemEntity, ItemDetail, BankEntity, BankItemEntity, BankName}; | ||||
| use crate::entity::character::CharacterEntityId; | ||||
| use crate::entity::item::tool::Tool; | ||||
| use crate::ship::items::inventory::{InventoryItemHandle, InventoryItem}; | ||||
| 
 | ||||
| const BANK_CAPACITY: usize = 200; | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct IndividualBankItem { | ||||
|     pub entity_id: ItemEntityId, | ||||
|     pub item_id: ClientItemId, | ||||
|     pub item: ItemDetail, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct StackedBankItem { | ||||
|     pub entity_ids: Vec<ItemEntityId>, | ||||
|     pub item_id: ClientItemId, | ||||
|     pub tool: Tool, | ||||
| } | ||||
| 
 | ||||
| impl StackedBankItem { | ||||
|     pub fn count(&self) -> usize { | ||||
|         self.entity_ids.len() | ||||
|     } | ||||
| 
 | ||||
|     pub fn take_entity_ids(&mut self, amount: usize) -> Option<Vec<ItemEntityId>> { | ||||
|         if amount <= self.count() { | ||||
|             Some(self.entity_ids.drain(..amount).collect()) | ||||
|         } | ||||
|         else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum BankItem { | ||||
|     Individual(IndividualBankItem), | ||||
|     Stacked(StackedBankItem), | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| impl std::cmp::PartialEq for BankItem { | ||||
|     fn eq(&self, other: &BankItem) -> bool { | ||||
|         let mut self_bytes = [0u8; 4]; | ||||
|         let mut other_bytes = [0u8; 4]; | ||||
|         self_bytes.copy_from_slice(&self.as_client_bytes()[0..4]); | ||||
|         other_bytes.copy_from_slice(&other.as_client_bytes()[0..4]); | ||||
| 
 | ||||
|         let self_value = u32::from_be_bytes(self_bytes); | ||||
|         let other_value = u32::from_be_bytes(other_bytes); | ||||
| 
 | ||||
|         self_value.eq(&other_value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl std::cmp::Eq for BankItem {} | ||||
| 
 | ||||
| impl std::cmp::PartialOrd for BankItem { | ||||
|     fn partial_cmp(&self, other: &BankItem) -> Option<std::cmp::Ordering> { | ||||
|         //let self_bytes = self.as_client_bytes();
 | ||||
|         //let other_bytes = other.as_client_bytes();
 | ||||
|         let mut self_bytes = [0u8; 4]; | ||||
|         let mut other_bytes = [0u8; 4]; | ||||
|         self_bytes.copy_from_slice(&self.as_client_bytes()[0..4]); | ||||
|         other_bytes.copy_from_slice(&other.as_client_bytes()[0..4]); | ||||
| 
 | ||||
| 
 | ||||
|         let self_value = u32::from_be_bytes(self_bytes); | ||||
|         let other_value = u32::from_be_bytes(other_bytes); | ||||
| 
 | ||||
|         self_value.partial_cmp(&other_value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl std::cmp::Ord for BankItem { | ||||
|     fn cmp(&self, other: &BankItem) -> std::cmp::Ordering { | ||||
|         //let self_bytes = self.as_client_bytes();
 | ||||
|         //let other_bytes = other.as_client_bytes();
 | ||||
|         let mut self_bytes = [0u8; 4]; | ||||
|         let mut other_bytes = [0u8; 4]; | ||||
|         self_bytes.copy_from_slice(&self.as_client_bytes()[0..4]); | ||||
|         other_bytes.copy_from_slice(&other.as_client_bytes()[0..4]); | ||||
| 
 | ||||
| 
 | ||||
|         let self_value = u32::from_le_bytes(self_bytes); | ||||
|         let other_value = u32::from_le_bytes(other_bytes); | ||||
| 
 | ||||
|         self_value.cmp(&other_value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl BankItem { | ||||
|     pub fn set_item_id(&mut self, item_id: ClientItemId) { | ||||
|         match self { | ||||
|             BankItem::Individual(individual_bank_item) => { | ||||
|                 individual_bank_item.item_id = item_id | ||||
|             }, | ||||
|             BankItem::Stacked(stacked_bank_item) => { | ||||
|                 stacked_bank_item.item_id = item_id | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn item_id(&self) -> ClientItemId { | ||||
|         match self { | ||||
|             BankItem::Individual(individual_bank_item) => { | ||||
|                 individual_bank_item.item_id | ||||
|             }, | ||||
|             BankItem::Stacked(stacked_bank_item) => { | ||||
|                 stacked_bank_item.item_id | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_client_bytes(&self) -> [u8; 16] { | ||||
|         match self { | ||||
|             BankItem::Individual(item) => { | ||||
|                 match &item.item { | ||||
|                     ItemDetail::Weapon(w) => w.as_bytes(), | ||||
|                     ItemDetail::Armor(a) => a.as_bytes(), | ||||
|                     ItemDetail::Shield(s) => s.as_bytes(), | ||||
|                     ItemDetail::Unit(u) => u.as_bytes(), | ||||
|                     ItemDetail::Tool(t) => t.as_individual_bytes(), | ||||
|                     ItemDetail::TechniqueDisk(d) => d.as_bytes(), | ||||
|                     ItemDetail::Mag(m) => m.as_bytes(), | ||||
|                     ItemDetail::ESWeapon(e) => e.as_bytes(), | ||||
|                 } | ||||
|             }, | ||||
|             BankItem::Stacked(item) => { | ||||
|                 item.tool.as_stacked_bytes(item.entity_ids.len()) | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| pub struct BankItemHandle<'a> { | ||||
|     bank: &'a mut CharacterBank, | ||||
|     index: usize | ||||
| } | ||||
| 
 | ||||
| impl<'a> BankItemHandle<'a> { | ||||
|     pub fn item(&'a self) -> Option<&'a BankItem> { | ||||
|         self.bank.items.get(self.index) | ||||
|     } | ||||
| 
 | ||||
|     pub fn item_mut(&mut self) -> Option<&mut BankItem> { | ||||
|         self.bank.items.get_mut(self.index) | ||||
|     } | ||||
| 
 | ||||
|     pub fn remove_from_bank(self) { | ||||
|         self.bank.items.remove(self.index); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct CharacterBank { | ||||
|     item_id_counter: u32, | ||||
|     items: Vec<BankItem> | ||||
| } | ||||
| 
 | ||||
| impl CharacterBank { | ||||
|     pub fn new(mut items: Vec<BankItem>) -> CharacterBank { | ||||
|         items.sort(); | ||||
|         CharacterBank { | ||||
|             item_id_counter: 0, | ||||
|             items, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn initialize_item_ids(&mut self, base_item_id: u32) { | ||||
|         for (i, item) in self.items.iter_mut().enumerate() { | ||||
|             item.set_item_id(ClientItemId(base_item_id + i as u32)); | ||||
|         } | ||||
|         self.item_id_counter = base_item_id + self.items.len() as u32 + 1; | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_item_handle_by_id(&mut self, item_id: ClientItemId) -> Option<BankItemHandle> { | ||||
|         let (index, _) = self.items.iter() | ||||
|             .enumerate() | ||||
|             .find(|(_, item)| { | ||||
|                 item.item_id() == item_id | ||||
|             })?; | ||||
|         Some(BankItemHandle { | ||||
|             bank: self, | ||||
|             index, | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_client_bank_items(&self) -> character::Bank { | ||||
|         self.items.iter() | ||||
|             .enumerate() | ||||
|             .fold(character::Bank::default(), |mut bank, (slot, item)| { | ||||
|                 bank.item_count = (slot + 1) as u32; | ||||
|                 let bytes = item.as_client_bytes(); | ||||
|                 bank.items[slot].data1.copy_from_slice(&bytes[0..12]); | ||||
|                 bank.items[slot].data2.copy_from_slice(&bytes[12..16]); | ||||
|                 bank.items[slot].item_id = item.item_id().0; | ||||
| 
 | ||||
|                 bank | ||||
|             }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_client_bank_request(&self) -> Vec<character::BankItem> { | ||||
|         self.items.iter() | ||||
|             .map(|item| { | ||||
|                 let bytes = item.as_client_bytes(); | ||||
|                 let mut data1 = [0; 12]; | ||||
|                 let mut data2 = [0; 4]; | ||||
|                 data1.copy_from_slice(&bytes[0..12]); | ||||
|                 data2.copy_from_slice(&bytes[12..16]); | ||||
|                 let amount = match item { | ||||
|                     BankItem::Individual(_individual_bank_item) => { | ||||
|                         1 | ||||
|                     }, | ||||
|                     BankItem::Stacked(stacked_bank_item) => { | ||||
|                         stacked_bank_item.count() | ||||
|                     }, | ||||
|                 }; | ||||
|                 character::BankItem { | ||||
|                     data1, | ||||
|                     data2, | ||||
|                     item_id: item.item_id().0, | ||||
|                     amount: amount as u16, | ||||
|                     flags: 1, | ||||
|                 } | ||||
|             }) | ||||
|             .collect() | ||||
|     } | ||||
| 
 | ||||
|     pub fn count(&self) -> usize { | ||||
|         self.items.len() | ||||
|     } | ||||
| 
 | ||||
|     pub fn deposit_item(&mut self, mut inventory_item: InventoryItemHandle, amount: usize) -> Option<&BankItem> { | ||||
|         let remove = match inventory_item.item_mut()? { | ||||
|             InventoryItem::Individual(individual_inventory_item) => { | ||||
|                 if self.items.len() >= BANK_CAPACITY { | ||||
|                     return None | ||||
|                 } | ||||
|                 self.items.push(BankItem::Individual(IndividualBankItem { | ||||
|                     entity_id: individual_inventory_item.entity_id, | ||||
|                     item_id: individual_inventory_item.item_id, | ||||
|                     item: individual_inventory_item.item.clone(), | ||||
|                 })); | ||||
|                 true | ||||
|             }, | ||||
|             InventoryItem::Stacked(stacked_inventory_item) => { | ||||
|                 let existing_bank_item = self.items.iter_mut() | ||||
|                     .find_map(|item| { | ||||
|                         if let BankItem::Stacked(stacked_bank_item) = item { | ||||
|                             if stacked_bank_item.tool == stacked_inventory_item.tool { | ||||
|                                 return Some(stacked_bank_item) | ||||
|                             } | ||||
|                         } | ||||
|                         None | ||||
|                     }); | ||||
| 
 | ||||
|                 match existing_bank_item { | ||||
|                     Some(stacked_bank_item) => { | ||||
|                         if stacked_bank_item.count() + stacked_inventory_item.count() > stacked_inventory_item.tool.max_stack() { | ||||
|                             return None | ||||
|                         } | ||||
| 
 | ||||
|                         let mut deposited_entity_ids = stacked_inventory_item.take_entity_ids(amount)?; | ||||
|                         stacked_bank_item.entity_ids.append(&mut deposited_entity_ids); | ||||
|                     } | ||||
|                     None => { | ||||
|                         if self.items.len() >= BANK_CAPACITY { | ||||
|                             return None | ||||
|                         } | ||||
|                         let deposited_entity_ids = stacked_inventory_item.take_entity_ids(amount)?; | ||||
| 
 | ||||
|                         self.item_id_counter += 1; | ||||
|                         self.items.push(BankItem::Stacked(StackedBankItem { | ||||
|                             entity_ids: deposited_entity_ids, | ||||
|                             item_id: ClientItemId(self.item_id_counter), | ||||
|                             tool: stacked_inventory_item.tool, | ||||
|                         })) | ||||
|                     } | ||||
|                 } | ||||
|                 stacked_inventory_item.count() == 0 | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         if remove { | ||||
|             inventory_item.remove_from_inventory(); | ||||
|         } | ||||
| 
 | ||||
|         self.items.last() | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_bank_entity(&self, _character_id: &CharacterEntityId, _bank_name: &BankName) -> BankEntity { | ||||
|         BankEntity { | ||||
|             items: self.items.iter() | ||||
|                 .map(|item| { | ||||
|                     match item { | ||||
|                         BankItem::Individual(item) => { | ||||
|                             BankItemEntity::Individual(ItemEntity { | ||||
|                                 id: item.entity_id, | ||||
|                                 item: item.item.clone(), | ||||
|                             }) | ||||
|                         }, | ||||
|                         BankItem::Stacked(items) => { | ||||
|                             BankItemEntity::Stacked(items.entity_ids.iter() | ||||
|                                                     .map(|id| { | ||||
|                                                         ItemEntity { | ||||
|                                                             id: *id, | ||||
|                                                             item: ItemDetail::Tool(items.tool) | ||||
|                                                         } | ||||
|                                                     }) | ||||
|                                                     .collect()) | ||||
|                         }, | ||||
|                     } | ||||
|                 }) | ||||
|                 .collect() | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -1,253 +0,0 @@ | ||||
| use crate::ship::items::ClientItemId; | ||||
| use crate::entity::item::{ItemEntityId, ItemDetail}; | ||||
| use crate::entity::item::Meseta; | ||||
| use crate::entity::item::tool::Tool; | ||||
| use crate::ship::map::MapArea; | ||||
| use crate::ship::items::inventory::{IndividualInventoryItem, StackedInventoryItem, InventoryItemHandle}; | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct IndividualFloorItem { | ||||
|     pub entity_id: ItemEntityId, | ||||
|     pub item_id: ClientItemId, | ||||
|     pub item: ItemDetail, | ||||
|     pub map_area: MapArea, | ||||
|     pub x: f32, | ||||
|     pub y: f32, | ||||
|     pub z: f32, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct StackedFloorItem { | ||||
|     pub entity_ids: Vec<ItemEntityId>, | ||||
|     pub item_id: ClientItemId, | ||||
|     pub tool: Tool, | ||||
|     pub map_area: MapArea, | ||||
|     pub x: f32, | ||||
|     pub y: f32, | ||||
|     pub z: f32, | ||||
| } | ||||
| 
 | ||||
| impl StackedFloorItem { | ||||
|     pub fn count(&self) -> usize { | ||||
|         self.entity_ids.len() | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_client_bytes(&self) -> [u8; 16] { | ||||
|         self.tool.as_stacked_bytes(self.count()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct MesetaFloorItem { | ||||
|     pub item_id: ClientItemId, | ||||
|     pub meseta: Meseta, | ||||
|     pub map_area: MapArea, | ||||
|     pub x: f32, | ||||
|     pub y: f32, | ||||
|     pub z: f32, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum FloorItem { | ||||
|     Individual(IndividualFloorItem), | ||||
|     Stacked(StackedFloorItem), | ||||
|     Meseta(MesetaFloorItem), | ||||
| } | ||||
| 
 | ||||
| impl FloorItem { | ||||
|     pub fn item_id(&self) -> ClientItemId { | ||||
|         match self { | ||||
|             FloorItem::Individual(individual_floor_item) => { | ||||
|                 individual_floor_item.item_id | ||||
|             }, | ||||
|             FloorItem::Stacked(stacked_floor_item) => { | ||||
|                 stacked_floor_item.item_id | ||||
|             }, | ||||
|             FloorItem::Meseta(meseta_floor_item) => { | ||||
|                 meseta_floor_item.item_id | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn x(&self) -> f32 { | ||||
|         match self { | ||||
|             FloorItem::Individual(individual_floor_item) => { | ||||
|                 individual_floor_item.x | ||||
|             }, | ||||
|             FloorItem::Stacked(stacked_floor_item) => { | ||||
|                 stacked_floor_item.x | ||||
|             }, | ||||
|             FloorItem::Meseta(meseta_floor_item) => { | ||||
|                 meseta_floor_item.x | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn y(&self) -> f32 { | ||||
|         match self { | ||||
|             FloorItem::Individual(individual_floor_item) => { | ||||
|                 individual_floor_item.y | ||||
|             }, | ||||
|             FloorItem::Stacked(stacked_floor_item) => { | ||||
|                 stacked_floor_item.y | ||||
|             }, | ||||
|             FloorItem::Meseta(meseta_floor_item) => { | ||||
|                 meseta_floor_item.y | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn z(&self) -> f32 { | ||||
|         match self { | ||||
|             FloorItem::Individual(individual_floor_item) => { | ||||
|                 individual_floor_item.z | ||||
|             }, | ||||
|             FloorItem::Stacked(stacked_floor_item) => { | ||||
|                 stacked_floor_item.z | ||||
|             }, | ||||
|             FloorItem::Meseta(meseta_floor_item) => { | ||||
|                 meseta_floor_item.z | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn map_area(&self) -> MapArea { | ||||
|         match self { | ||||
|             FloorItem::Individual(individual_floor_item) => { | ||||
|                 individual_floor_item.map_area | ||||
|             }, | ||||
|             FloorItem::Stacked(stacked_floor_item) => { | ||||
|                 stacked_floor_item.map_area | ||||
|             }, | ||||
|             FloorItem::Meseta(meseta_floor_item) => { | ||||
|                 meseta_floor_item.map_area | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_client_bytes(&self) -> [u8; 16] { | ||||
|         match self { | ||||
|             FloorItem::Individual(individual_floor_item) => { | ||||
|                 individual_floor_item.item.as_client_bytes() | ||||
|             }, | ||||
|             FloorItem::Stacked(stacked_floor_item) => { | ||||
|                 stacked_floor_item.as_client_bytes() | ||||
|             }, | ||||
|             FloorItem::Meseta(meseta_floor_item) => { | ||||
|                 meseta_floor_item.meseta.as_bytes() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| pub struct FloorItemHandle<'a> { | ||||
|     floor: &'a mut RoomFloorItems, | ||||
|     index: usize, | ||||
| } | ||||
| 
 | ||||
| impl<'a> FloorItemHandle<'a> { | ||||
|     pub fn item(&'a self) -> Option<&'a FloorItem> { | ||||
|         self.floor.0.get(self.index) | ||||
|     } | ||||
| 
 | ||||
|     pub fn remove_from_floor(self) { | ||||
|         self.floor.0.remove(self.index); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // TODO: floors should keep track of their own item_ids
 | ||||
| #[derive(Debug, Default)] | ||||
| pub struct RoomFloorItems(Vec<FloorItem>); | ||||
| 
 | ||||
| impl RoomFloorItems { | ||||
|     pub fn add_item(&mut self, item: FloorItem) { | ||||
|         self.0.push(item); | ||||
|     } | ||||
| 
 | ||||
|     pub fn remove_item(&mut self, item_id: &ClientItemId) { | ||||
|         self.0.retain(|item| item.item_id() != *item_id); | ||||
|     } | ||||
| 
 | ||||
|     // TODO: &ClientItemId
 | ||||
|     pub fn get_item_by_id(&self, item_id: ClientItemId) -> Option<&FloorItem> { | ||||
|         self.0.iter().find(|item| item.item_id() == item_id) | ||||
|     } | ||||
| 
 | ||||
|     // TODO: &ClientItemId
 | ||||
|     pub fn get_item_handle_by_id(&mut self, item_id: ClientItemId) -> Option<FloorItemHandle> { | ||||
|         let index = self.0.iter().position(|item| item.item_id() == item_id)?; | ||||
|         Some(FloorItemHandle { | ||||
|             floor: self, | ||||
|             index, | ||||
|         }) | ||||
|     } | ||||
|     
 | ||||
|     pub fn take_item_by_id(&mut self, item_id: ClientItemId) -> Option<FloorItem> { | ||||
|         self.0 | ||||
|             .drain_filter(|i| i.item_id() == item_id) | ||||
|             .next() | ||||
|     } | ||||
| 
 | ||||
|     pub fn drop_individual_inventory_item(&mut self, individual_inventory_item: IndividualInventoryItem, item_drop_location: (MapArea, f32, f32, f32)) -> &IndividualFloorItem { | ||||
|         self.0.push(FloorItem::Individual(IndividualFloorItem { | ||||
|             entity_id: individual_inventory_item.entity_id, | ||||
|             item_id: individual_inventory_item.item_id, | ||||
|             item: individual_inventory_item.item, | ||||
|             map_area: item_drop_location.0, | ||||
|             x: item_drop_location.1, | ||||
|             y: item_drop_location.2, | ||||
|             z: item_drop_location.3, | ||||
|         })); | ||||
| 
 | ||||
|         match self.0.last().unwrap() { | ||||
|             FloorItem::Individual(item) => item, | ||||
|             _ => unreachable!(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn drop_stacked_inventory_item(&mut self, stacked_inventory_item: StackedInventoryItem, item_drop_location: (MapArea, f32, f32, f32)) -> &StackedFloorItem { | ||||
|         self.0.push(FloorItem::Stacked(StackedFloorItem { | ||||
|             entity_ids: stacked_inventory_item.entity_ids, | ||||
|             item_id: stacked_inventory_item.item_id, | ||||
|             tool: stacked_inventory_item.tool, | ||||
|             map_area: item_drop_location.0, | ||||
|             x: item_drop_location.1, | ||||
|             y: item_drop_location.2, | ||||
|             z: item_drop_location.3, | ||||
|         })); | ||||
|             
 | ||||
|         match self.0.last().unwrap() { | ||||
|             FloorItem::Stacked(item) => item, | ||||
|             _ => unreachable!(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // TODO: Result
 | ||||
|     // TODO: if consumed_item is not a tool items do not get placed back into inventory (should I care?)
 | ||||
|     pub fn drop_partial_stacked_inventory_item(&mut self, inventory_item: InventoryItemHandle, amount: usize, new_item_id: ClientItemId, item_drop_location: (MapArea, f32, f32, f32)) -> Option<&StackedFloorItem> { | ||||
|         let consumed_item = inventory_item.consume(amount).ok()?; | ||||
| 
 | ||||
|         if let ItemDetail::Tool(tool) = consumed_item.item() { | ||||
|             self.0.push(FloorItem::Stacked(StackedFloorItem { | ||||
|                 entity_ids: consumed_item.entity_ids(), | ||||
|                 item_id: new_item_id, | ||||
|                 tool, | ||||
|                 map_area: item_drop_location.0, | ||||
|                 x: item_drop_location.1, | ||||
|                 y: item_drop_location.2, | ||||
|                 z: item_drop_location.3, | ||||
|             })) | ||||
|         } | ||||
|         else { | ||||
|             return None | ||||
|         } | ||||
| 
 | ||||
|         match self.0.last().unwrap() { | ||||
|             FloorItem::Stacked(item) => Some(item), | ||||
|             _ => unreachable!(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -21,7 +21,6 @@ use crate::ship::packet::handler::trade::{TradeError, OTHER_MESETA_ITEM_ID}; | ||||
| use crate::ship::items::bank::*; | ||||
| use crate::ship::items::floor::*; | ||||
| use crate::ship::items::inventory::*; | ||||
| use crate::ship::items::use_tool; | ||||
| use crate::ship::items::transaction::{ItemTransaction, ItemAction, TransactionError, TransactionCommitError}; | ||||
| use crate::ship::monster::MonsterType; | ||||
| 
 | ||||
|  | ||||
| @ -1,9 +1,3 @@ | ||||
| mod bank; | ||||
| mod floor; | ||||
| pub mod inventory; | ||||
| pub mod manager; | ||||
| pub mod transaction; | ||||
| pub mod use_tool; | ||||
| pub mod state; | ||||
| pub mod actions; | ||||
| pub mod apply_item; | ||||
| @ -12,10 +6,4 @@ use serde::{Serialize, Deserialize}; | ||||
| #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, derive_more::Display)] | ||||
| pub struct ClientItemId(pub u32); | ||||
| 
 | ||||
| // TODO: remove these and fix use statements in the rest of the codebase
 | ||||
| pub use inventory::*; | ||||
| pub use floor::*; | ||||
| pub use bank::*; | ||||
| pub use manager::*; | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -1,337 +0,0 @@ | ||||
| use crate::entity::gateway::EntityGateway; | ||||
| use thiserror::Error; | ||||
| use crate::ship::items::manager::{ItemManager, ItemManagerError}; | ||||
| use crate::entity::gateway::GatewayError; | ||||
| 
 | ||||
| #[derive(Error, Debug)] | ||||
| pub enum TransactionCommitError { | ||||
|     #[error("transaction commit gateway error {0}")] | ||||
|     Gateway(#[from] GatewayError), | ||||
|     #[error("transaction commit itemmanager error {0}")] | ||||
|     ItemManager(#[from] ItemManagerError), | ||||
| } | ||||
| 
 | ||||
| #[async_trait::async_trait] | ||||
| pub trait ItemAction<EG: EntityGateway>: std::marker::Send + std::marker::Sync + std::fmt::Debug { | ||||
|     async fn commit(&self, manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError>; | ||||
| } | ||||
| 
 | ||||
| pub struct ItemTransactionActions<'a, EG: EntityGateway> { | ||||
|     action_queue: Vec<Box<dyn ItemAction<EG>>>, | ||||
|     pub manager: &'a ItemManager, | ||||
| } | ||||
| 
 | ||||
|     
 | ||||
| impl<'a, EG: EntityGateway> ItemTransactionActions<'a, EG> { | ||||
|     fn new(manager: &'a ItemManager) -> ItemTransactionActions<'a, EG> { | ||||
|         ItemTransactionActions { | ||||
|             action_queue: Vec::new(), | ||||
|             manager | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn action(&mut self, action: Box<dyn ItemAction<EG>>) { | ||||
|         self.action_queue.push(action) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| pub struct ItemTransaction<'a, T, EG: EntityGateway> { | ||||
|     data: T, | ||||
|     actions: ItemTransactionActions<'a, EG>, | ||||
| } | ||||
| 
 | ||||
| impl<'a, T, EG: EntityGateway> ItemTransaction<'a, T, EG> { | ||||
|     pub fn new(manager: &'a ItemManager, arg: T) -> ItemTransaction<'a, T, EG> { | ||||
|         ItemTransaction { | ||||
|             data: arg, | ||||
|             actions: ItemTransactionActions::new(manager), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn act<E: std::fmt::Debug, U>(mut self, action: fn(&mut ItemTransactionActions<EG>, &T) -> Result<U, E>) -> FinalizedItemTransaction<U, E, EG> { | ||||
|         match action(&mut self.actions, &self.data) { | ||||
|             Ok(k) => { | ||||
|                 FinalizedItemTransaction { | ||||
|                     value: Ok(k), | ||||
|                     action_queue: self.actions.action_queue, | ||||
|                 } | ||||
|             }, | ||||
|             Err(err) => { | ||||
|                 FinalizedItemTransaction { | ||||
|                     value: Err(err), | ||||
|                     action_queue: Vec::new(), | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Error, Debug)] | ||||
| pub enum TransactionError<E: std::fmt::Debug> { | ||||
|     #[error("transaction action error {0:?}")] | ||||
|     Action(E), | ||||
|     #[error("transaction commit error {0}")] | ||||
|     Commit(#[from] TransactionCommitError), | ||||
|     
 | ||||
| } | ||||
| 
 | ||||
| // this only exists to drop the ItemManager borrow of ItemTransaction so a mutable ItemTransaction can be passed in later
 | ||||
| pub struct FinalizedItemTransaction<T, E: std::fmt::Debug, EG: EntityGateway> { | ||||
|     value: Result<T, E>, | ||||
|     action_queue: Vec<Box<dyn ItemAction<EG>>>, | ||||
| } | ||||
| 
 | ||||
| impl<T, E: std::fmt::Debug, EG: EntityGateway> FinalizedItemTransaction<T, E, EG> { | ||||
|     pub async fn commit(self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<T, TransactionError<E>> { | ||||
|         match self.value { | ||||
|             Ok(value) => { | ||||
|                 for action in self.action_queue.into_iter() { | ||||
|                     // TODO: better handle rolling back if this ever errors out
 | ||||
|                     action.commit(item_manager, entity_gateway).await.map_err(|err| TransactionError::Commit(err))?; | ||||
|                 } | ||||
|                 Ok(value) | ||||
|             }, | ||||
|             Err(err) => Err(TransactionError::Action(err)), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod test { | ||||
|     use super::*; | ||||
|     use crate::entity::account::{UserAccountId, NewUserAccountEntity, UserAccountEntity}; | ||||
|     use crate::entity::character::{NewCharacterEntity, CharacterEntity}; | ||||
|     use crate::entity::gateway::GatewayError; | ||||
|     use thiserror::Error; | ||||
|     
 | ||||
|     #[async_std::test] | ||||
|     async fn test_item_transaction() { | ||||
|         #[derive(Debug)] | ||||
|         struct DummyAction1 { | ||||
|             name: String, | ||||
|         } | ||||
|         #[derive(Debug)] | ||||
|         struct DummyAction2 { | ||||
|             value: u32, | ||||
|         } | ||||
| 
 | ||||
|         #[derive(Error, Debug)] | ||||
|         #[error("")] | ||||
|         enum DummyError { | ||||
|             Error | ||||
|         } | ||||
| 
 | ||||
|         #[derive(Default, Clone)] | ||||
|         struct DummyGateway { | ||||
|             d1_set: String, | ||||
|             d2_inc: u32, | ||||
|         } | ||||
| 
 | ||||
|         #[async_trait::async_trait] | ||||
|         impl EntityGateway for DummyGateway { | ||||
|             async fn create_user(&mut self, user: NewUserAccountEntity) -> Result<UserAccountEntity, GatewayError> { | ||||
|                 self.d1_set = user.username; | ||||
|                 Ok(UserAccountEntity::default()) | ||||
|             } | ||||
| 
 | ||||
|             async fn create_character(&mut self, char: NewCharacterEntity) -> Result<CharacterEntity, GatewayError> { | ||||
|                 self.d2_inc += char.slot; | ||||
|                 Ok(CharacterEntity::default()) | ||||
|             } | ||||
|         } | ||||
|         
 | ||||
| 
 | ||||
|         #[async_trait::async_trait] | ||||
|         impl<EG: EntityGateway> ItemAction<EG> for DummyAction1 { | ||||
|             async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { | ||||
|                 item_manager.id_counter = 55555; | ||||
|                 entity_gateway.create_user(NewUserAccountEntity { | ||||
|                     username: self.name.clone(), | ||||
|                     ..NewUserAccountEntity::default() | ||||
|                 }) | ||||
|                     .await?; | ||||
|                 Ok(()) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #[async_trait::async_trait] | ||||
|         impl<EG: EntityGateway> ItemAction<EG> for DummyAction2 { | ||||
|             async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { | ||||
|                 item_manager.id_counter += self.value; | ||||
|                 entity_gateway.create_character(NewCharacterEntity { | ||||
|                     slot: self.value, | ||||
|                     ..NewCharacterEntity::new(UserAccountId(0), 1) // TODO: handle different keyboard_config_presets
 | ||||
|                 }) | ||||
|                     .await?; | ||||
|                 Ok(()) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         let mut item_manager = ItemManager::default(); | ||||
|         let mut entity_gateway = DummyGateway::default(); | ||||
| 
 | ||||
|         let result = ItemTransaction::new(&item_manager, 12) | ||||
|             .act(|it, k| { | ||||
|                 it.action(Box::new(DummyAction1 {name: "asdf".into()})); | ||||
|                 it.action(Box::new(DummyAction2 {value: 11})); | ||||
|                 it.action(Box::new(DummyAction2 {value: *k})); | ||||
|                 if *k == 99 { | ||||
|                     return Err(DummyError::Error) | ||||
|                 } | ||||
|                 Ok(String::from("hello")) | ||||
|             }) | ||||
|             .commit(&mut item_manager, &mut entity_gateway) | ||||
|             .await; | ||||
| 
 | ||||
|         assert!(entity_gateway.d1_set == "asdf"); | ||||
|         assert!(entity_gateway.d2_inc == 23); | ||||
|         assert!(item_manager.id_counter == 55578); | ||||
|         assert!(result.unwrap() == "hello"); | ||||
|     } | ||||
| 
 | ||||
|     #[async_std::test] | ||||
|     async fn test_item_transaction_with_action_error() { | ||||
|         #[derive(Debug)] | ||||
|         struct DummyAction1 { | ||||
|         } | ||||
|         #[derive(Debug)] | ||||
|         struct DummyAction2 { | ||||
|         } | ||||
| 
 | ||||
|         #[derive(Error, Debug, PartialEq, Eq)] | ||||
|         #[error("")] | ||||
|         enum DummyError { | ||||
|             Error | ||||
|         } | ||||
| 
 | ||||
|         #[derive(Default, Clone)] | ||||
|         struct DummyGateway { | ||||
|             _d1_set: String, | ||||
|             d2_inc: u32, | ||||
|         } | ||||
| 
 | ||||
|         #[async_trait::async_trait] | ||||
|         impl EntityGateway for DummyGateway { | ||||
|             async fn create_character(&mut self, char: NewCharacterEntity) -> Result<CharacterEntity, GatewayError> { | ||||
|                 self.d2_inc += char.slot; | ||||
|                 Ok(CharacterEntity::default()) | ||||
|             } | ||||
|         } | ||||
|         
 | ||||
| 
 | ||||
|         #[async_trait::async_trait] | ||||
|         impl<EG: EntityGateway> ItemAction<EG> for DummyAction1 { | ||||
|             async fn commit(&self, _item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { | ||||
|                 entity_gateway.create_character(NewCharacterEntity { | ||||
|                     slot: 1, | ||||
|                     ..NewCharacterEntity::new(UserAccountId(0), 1) // TODO: handle different keyboard_config_presets
 | ||||
|                 }) | ||||
|                     .await?; | ||||
|                 Ok(()) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #[async_trait::async_trait] | ||||
|         impl<EG: EntityGateway> ItemAction<EG> for DummyAction2 { | ||||
|             async fn commit(&self, _item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { | ||||
|                 entity_gateway.create_character(NewCharacterEntity { | ||||
|                     slot: 1, | ||||
|                     ..NewCharacterEntity::new(UserAccountId(0), 1) // TODO: handle different keyboard_config_presets
 | ||||
|                 }) | ||||
|                     .await?; | ||||
|                 Ok(()) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         let mut item_manager = ItemManager::default(); | ||||
|         let mut entity_gateway = DummyGateway::default(); | ||||
| 
 | ||||
|         let result = ItemTransaction::new(&item_manager, 12) | ||||
|             .act(|it, _| -> Result<(), _> { | ||||
|                 it.action(Box::new(DummyAction1 {})); | ||||
|                 it.action(Box::new(DummyAction2 {})); | ||||
|                 it.action(Box::new(DummyAction2 {})); | ||||
|                 Err(DummyError::Error) | ||||
|             }) | ||||
|             .commit(&mut item_manager, &mut entity_gateway) | ||||
|             .await; | ||||
| 
 | ||||
|         assert!(entity_gateway.d2_inc == 0); | ||||
|         assert!(matches!(result, Err(TransactionError::Action(DummyError::Error)))); | ||||
|     } | ||||
| 
 | ||||
|     #[async_std::test] | ||||
|     async fn test_item_transaction_with_commit_error() { | ||||
|         #[derive(Debug)] | ||||
|         struct DummyAction1 { | ||||
|         } | ||||
|         #[derive(Debug)] | ||||
|         struct DummyAction2 { | ||||
|         } | ||||
| 
 | ||||
|         #[derive(Error, Debug, PartialEq, Eq)] | ||||
|         #[error("")] | ||||
|         enum DummyError { | ||||
|         } | ||||
| 
 | ||||
|         #[derive(Default, Clone)] | ||||
|         struct DummyGateway { | ||||
|             _d1_set: String, | ||||
|             d2_inc: u32, | ||||
|         } | ||||
| 
 | ||||
|         #[async_trait::async_trait] | ||||
|         impl EntityGateway for DummyGateway { | ||||
|             async fn create_character(&mut self, char: NewCharacterEntity) -> Result<CharacterEntity, GatewayError> { | ||||
|                 self.d2_inc += char.slot; | ||||
|                 Ok(CharacterEntity::default()) | ||||
|             } | ||||
|         } | ||||
|         
 | ||||
| 
 | ||||
|         #[async_trait::async_trait] | ||||
|         impl<EG: EntityGateway> ItemAction<EG> for DummyAction1 { | ||||
|             async fn commit(&self, _item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { | ||||
|                 entity_gateway.create_character(NewCharacterEntity { | ||||
|                     slot: 1, | ||||
|                     ..NewCharacterEntity::new(UserAccountId(0), 1) // TODO: handle different keyboard_config_presets
 | ||||
|                 }) | ||||
|                     .await?; | ||||
|                 Err(GatewayError::Error.into()) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #[async_trait::async_trait] | ||||
|         impl<EG: EntityGateway> ItemAction<EG> for DummyAction2 { | ||||
|             async fn commit(&self, _item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { | ||||
|                 entity_gateway.create_character(NewCharacterEntity { | ||||
|                     slot: 1, | ||||
|                     ..NewCharacterEntity::new(UserAccountId(0), 1) // TODO: handle different keyboard_config_presets
 | ||||
|                 }) | ||||
|                     .await?; | ||||
|                 Ok(()) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         let mut item_manager = ItemManager::default(); | ||||
|         let mut entity_gateway = DummyGateway::default(); | ||||
| 
 | ||||
|         let result = ItemTransaction::new(&item_manager, 12) | ||||
|             .act(|it, _| -> Result<_, DummyError> { | ||||
|                 it.action(Box::new(DummyAction1 {})); | ||||
|                 it.action(Box::new(DummyAction2 {})); | ||||
|                 it.action(Box::new(DummyAction2 {})); | ||||
|                 Ok(()) | ||||
|             }) | ||||
|             .commit(&mut item_manager, &mut entity_gateway) | ||||
|             .await; | ||||
| 
 | ||||
|         // in an ideal world this would be 0 as rollbacks would occur
 | ||||
|         assert!(entity_gateway.d2_inc == 1); | ||||
|         assert!(matches!(result, Err(TransactionError::Commit(TransactionCommitError::Gateway(GatewayError::Error))))); | ||||
|     } | ||||
| } | ||||
|         
 | ||||
| @ -1,163 +0,0 @@ | ||||
| use thiserror::Error; | ||||
| use crate::entity::gateway::EntityGateway; | ||||
| use crate::entity::character::CharacterEntity; | ||||
| use crate::entity::item::mag::MagCell; | ||||
| use crate::ship::items::{CharacterInventory, ConsumedItem}; | ||||
| 
 | ||||
| #[derive(Error, Debug)] | ||||
| #[error("")] | ||||
| pub enum UseItemError { | ||||
|     NoCharacter, | ||||
|     ItemNotEquipped, | ||||
|     InvalidItem, | ||||
| } | ||||
| 
 | ||||
| pub async fn power_material<EG: EntityGateway>(entity_gateway: &mut EG, character: &mut CharacterEntity) { | ||||
|     character.materials.power += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
| } | ||||
| 
 | ||||
| pub async fn mind_material<EG: EntityGateway>(entity_gateway: &mut EG, character: &mut CharacterEntity) { | ||||
|     character.materials.mind += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
| } | ||||
| 
 | ||||
| pub async fn evade_material<EG: EntityGateway>(entity_gateway: &mut EG, character: &mut CharacterEntity) { | ||||
|     character.materials.evade += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
| } | ||||
| 
 | ||||
| pub async fn def_material<EG: EntityGateway>(entity_gateway: &mut EG, character: &mut CharacterEntity) { | ||||
|     character.materials.def += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
| } | ||||
| 
 | ||||
| pub async fn luck_material<EG: EntityGateway>(entity_gateway: &mut EG, character: &mut CharacterEntity) { | ||||
|     character.materials.luck += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
| } | ||||
| 
 | ||||
| pub async fn hp_material<EG: EntityGateway>(entity_gateway: &mut EG, character: &mut CharacterEntity) { | ||||
|     character.materials.hp += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
| } | ||||
| 
 | ||||
| pub async fn tp_material<EG: EntityGateway>(entity_gateway: &mut EG, character: &mut CharacterEntity) { | ||||
|     character.materials.tp += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
| } | ||||
| 
 | ||||
| async fn mag_cell<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory, mag_cell_type: MagCell) -> Result<(), UseItemError> { | ||||
|     let mut mag_handle = inventory.get_equipped_mag_handle().ok_or(UseItemError::ItemNotEquipped)?; | ||||
|     let mag_item = mag_handle.item_mut() | ||||
|         .ok_or(UseItemError::InvalidItem)?; | ||||
|     let actual_mag = mag_item | ||||
|         .individual_mut() | ||||
|         .ok_or(UseItemError::InvalidItem)? | ||||
|         .mag_mut() | ||||
|         .ok_or(UseItemError::InvalidItem)?; | ||||
|     actual_mag.apply_mag_cell(mag_cell_type); | ||||
|     for mag_entity_id in mag_item.entity_ids() { | ||||
|         for cell_entity_id in used_cell.entity_ids() { | ||||
|             entity_gateway.use_mag_cell(&mag_entity_id, &cell_entity_id).await.unwrap(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| pub async fn cell_of_mag_502<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::CellOfMag502).await | ||||
| } | ||||
| 
 | ||||
| pub async fn cell_of_mag_213<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::CellOfMag213).await | ||||
| } | ||||
| 
 | ||||
| pub async fn parts_of_robochao<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::PartsOfRobochao).await | ||||
| } | ||||
| 
 | ||||
| pub async fn heart_of_opaopa<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfOpaOpa).await | ||||
| } | ||||
| 
 | ||||
| pub async fn heart_of_pian<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfPian).await | ||||
| } | ||||
| 
 | ||||
| pub async fn heart_of_chao<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfChao).await | ||||
| } | ||||
| 
 | ||||
| pub async fn heart_of_angel<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfAngel).await | ||||
| } | ||||
| 
 | ||||
| pub async fn kit_of_hamburger<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfHamburger).await | ||||
| } | ||||
| 
 | ||||
| pub async fn panthers_spirit<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::PanthersSpirit).await | ||||
| } | ||||
| 
 | ||||
| pub async fn kit_of_mark3<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfMark3).await | ||||
| } | ||||
| 
 | ||||
| pub async fn kit_of_master_system<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfMasterSystem).await | ||||
| } | ||||
| 
 | ||||
| pub async fn kit_of_genesis<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfGenesis).await | ||||
| } | ||||
| 
 | ||||
| pub async fn kit_of_sega_saturn<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfSegaSaturn).await | ||||
| } | ||||
| 
 | ||||
| pub async fn kit_of_dreamcast<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfDreamcast).await | ||||
| } | ||||
| 
 | ||||
| pub async fn tablet<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::Tablet).await | ||||
| } | ||||
| 
 | ||||
| pub async fn dragon_scale<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::DragonScale).await | ||||
| } | ||||
| 
 | ||||
| pub async fn heaven_striker_coat<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::HeavenStrikerCoat).await | ||||
| } | ||||
| 
 | ||||
| pub async fn pioneer_parts<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::PioneerParts).await | ||||
| } | ||||
| 
 | ||||
| pub async fn amities_memo<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::AmitiesMemo).await | ||||
| } | ||||
| 
 | ||||
| pub async fn heart_of_morolian<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfMorolian).await | ||||
| } | ||||
| 
 | ||||
| pub async fn rappys_beak<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::RappysBeak).await | ||||
| } | ||||
| 
 | ||||
| pub async fn yahoos_engine<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::YahoosEngine).await | ||||
| } | ||||
| 
 | ||||
| pub async fn d_photon_core<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::DPhotonCore).await | ||||
| } | ||||
| 
 | ||||
| pub async fn liberta_kit<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::LibertaKit).await | ||||
| } | ||||
| @ -5,7 +5,6 @@ use crate::ship::ship::{ShipError, Clients}; | ||||
| use crate::ship::location::{ClientLocation, LobbyId, ClientLocationError}; | ||||
| use crate::ship::packet::builder::{player_info}; | ||||
| use crate::ship::items::state::ItemState; | ||||
| use crate::ship::items::ItemManager; | ||||
| 
 | ||||
| 
 | ||||
| pub fn join_lobby(id: ClientId, | ||||
|  | ||||
| @ -3,16 +3,14 @@ use libpso::packet::ship::*; | ||||
| use crate::entity::item; | ||||
| use crate::common::leveltable::CharacterStats; | ||||
| use crate::ship::ship::{ShipError}; | ||||
| use crate::ship::items::{ClientItemId, InventoryItem, StackedFloorItem, FloorItem, CharacterBank}; | ||||
| use crate::ship::items::state::FloorItem as FloorItem2; | ||||
| use crate::ship::items::state::InventoryItem as InventoryItem2; | ||||
| use crate::ship::items::state::{BankState, IndividualItemDetail}; | ||||
| use crate::ship::items::ClientItemId; | ||||
| use crate::ship::items::state::{InventoryItem, FloorItem, BankState, IndividualItemDetail}; | ||||
| use crate::ship::location::AreaClient; | ||||
| use std::convert::TryInto; | ||||
| use crate::ship::shops::ShopItem; | ||||
| 
 | ||||
| 
 | ||||
| pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem2) -> Result<ItemDrop, ShipError> { | ||||
| pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> Result<ItemDrop, ShipError> { | ||||
|     let item_bytes = item_drop.as_client_bytes(); | ||||
|     Ok(ItemDrop { | ||||
|         client, | ||||
| @ -68,7 +66,7 @@ pub fn create_meseta(area_client: AreaClient, amount: usize) -> CreateItem { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn create_withdrawn_inventory_item(area_client: AreaClient, item: &InventoryItem2) -> Result<CreateItem, ShipError> { | ||||
| pub fn create_withdrawn_inventory_item(area_client: AreaClient, item: &InventoryItem) -> Result<CreateItem, ShipError> { | ||||
|     let bytes = item.item.as_client_bytes(); | ||||
|     Ok(CreateItem { | ||||
|         client: area_client.local_client.id(), | ||||
| @ -80,7 +78,7 @@ pub fn create_withdrawn_inventory_item(area_client: AreaClient, item: &Inventory | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
| pub fn create_withdrawn_inventory_item2(area_client: AreaClient, item: &InventoryItem2) -> Result<CreateItem, ShipError> { | ||||
| pub fn create_withdrawn_inventory_item2(area_client: AreaClient, item: &InventoryItem) -> Result<CreateItem, ShipError> { | ||||
|     let bytes = item.item.as_client_bytes(); | ||||
|     Ok(CreateItem { | ||||
|         client: area_client.local_client.id(), | ||||
| @ -92,7 +90,7 @@ pub fn create_withdrawn_inventory_item2(area_client: AreaClient, item: &Inventor | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
| pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem2) -> Result<RemoveItemFromFloor, ShipError> { | ||||
| pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem) -> Result<RemoveItemFromFloor, ShipError> { | ||||
|     Ok(RemoveItemFromFloor { | ||||
|         client: area_client.local_client.id(), | ||||
|         target: 0, | ||||
| @ -104,7 +102,7 @@ pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem2) -> Res | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
| pub fn drop_split_stack(area_client: AreaClient, item: &FloorItem2) -> Result<DropSplitStack, ShipError> { | ||||
| pub fn drop_split_stack(area_client: AreaClient, item: &FloorItem) -> Result<DropSplitStack, ShipError> { | ||||
|     let item_bytes = item.as_client_bytes(); | ||||
|     Ok(DropSplitStack { | ||||
|         client: area_client.local_client.id(), | ||||
| @ -121,7 +119,7 @@ pub fn drop_split_stack(area_client: AreaClient, item: &FloorItem2) -> Result<Dr | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
| pub fn drop_split_meseta_stack(area_client: AreaClient, item: &FloorItem2) -> Result<DropSplitStack, ShipError> { | ||||
| pub fn drop_split_meseta_stack(area_client: AreaClient, item: &FloorItem) -> Result<DropSplitStack, ShipError> { | ||||
|     let item_bytes = item.as_client_bytes(); | ||||
|     Ok(DropSplitStack { | ||||
|         client: area_client.local_client.id(), | ||||
|  | ||||
| @ -5,7 +5,6 @@ use crate::ship::ship::{ShipError, ClientState, Clients}; | ||||
| use crate::ship::location::{ClientLocation, RoomId, AreaClient, ClientLocationError}; | ||||
| use crate::ship::room::RoomState; | ||||
| use crate::ship::items::state::ItemState; | ||||
| use crate::ship::items::ItemManager; | ||||
| use crate::ship::packet::builder::{player_header, player_info}; | ||||
| use std::convert::TryInto; | ||||
| 
 | ||||
|  | ||||
| @ -8,13 +8,13 @@ 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, FloorItem}; | ||||
| use crate::ship::items::ClientItemId; | ||||
| 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::state::{ItemState, ItemStateError, FloorType, FloorItemDetail}; | ||||
| use crate::ship::items::actions::{pick_up_item, withdraw_meseta, deposit_meseta, withdraw_item, deposit_item, buy_shop_item, enemy_drops_item, take_meseta, apply_modifier, TriggerCreateItem}; | ||||
| 
 | ||||
| const BANK_ACTION_DEPOSIT: u8 = 0; | ||||
| @ -437,11 +437,11 @@ where | ||||
| 
 | ||||
|     let inventory = item_state.get_character_inventory(&client.character)?; | ||||
|     let item = inventory.get_by_client_id(&ClientItemId(tek_request.item_id)) | ||||
|         .ok_or(ItemManagerError::WrongItemType(ClientItemId(tek_request.item_id)))?; | ||||
|         .ok_or(ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))?; | ||||
|     let mut weapon = item.item.as_individual() | ||||
|         .ok_or(ItemManagerError::WrongItemType(ClientItemId(tek_request.item_id)))? | ||||
|         .ok_or(ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))? | ||||
|         .as_weapon() | ||||
|         .ok_or(ItemManagerError::WrongItemType(ClientItemId(tek_request.item_id)))? | ||||
|         .ok_or(ItemStateError::WrongItemType(ClientItemId(tek_request.item_id)))? | ||||
|         .clone(); | ||||
| 
 | ||||
|     weapon.apply_modifier(&item::weapon::WeaponModifier::Tekked { | ||||
|  | ||||
| @ -61,7 +61,6 @@ pub enum ShipError { | ||||
|     ItemError, // TODO: refine this
 | ||||
|     PickUpInvalidItemId(u32), | ||||
|     DropInvalidItemId(u32), | ||||
|     ItemManagerError(#[from] items::ItemManagerError), | ||||
|     ItemStateError(#[from] items::state::ItemStateError), | ||||
|     #[error("")] | ||||
|     ItemDropLocationNotSet, | ||||
| @ -406,7 +405,6 @@ impl<EG: EntityGateway> ShipServerStateBuilder<EG> { | ||||
|             clients: HashMap::new(), | ||||
|             level_table: CharacterLevelTable::default(), | ||||
|             name: self.name.unwrap_or_else(|| "NAMENOTSET".into()), | ||||
|             item_manager: items::ItemManager::default(), | ||||
|             item_state: items::state::ItemState::default(), | ||||
|             ip: self.ip.unwrap_or_else(|| Ipv4Addr::new(127,0,0,1)), | ||||
|             port: self.port.unwrap_or(SHIP_PORT), | ||||
| @ -451,7 +449,6 @@ pub struct ShipServerState<EG: EntityGateway> { | ||||
|     pub clients: Clients, | ||||
|     level_table: CharacterLevelTable, | ||||
|     name: String, | ||||
|     item_manager: items::ItemManager, | ||||
|     item_state: items::state::ItemState, | ||||
|     shops: Box<ItemShops>, | ||||
|     pub blocks: Blocks, | ||||
|  | ||||
| @ -3,7 +3,6 @@ use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; | ||||
| use elseware::entity::item; | ||||
| use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; | ||||
| use elseware::ship::room::Difficulty; | ||||
| use elseware::ship::items::manager::ItemManagerError; | ||||
| use elseware::ship::items::state::ItemStateError; | ||||
| 
 | ||||
| use libpso::packet::ship::*; | ||||
|  | ||||
| @ -4,7 +4,6 @@ use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; | ||||
| use elseware::entity::item; | ||||
| use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket, ShipError}; | ||||
| use elseware::entity::item::{Meseta, ItemEntity}; | ||||
| use elseware::ship::items::transaction::TransactionError; | ||||
| use elseware::ship::packet::handler::trade::TradeError; | ||||
| use elseware::ship::items::state::{ItemStateError, InventoryError}; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user