diff --git a/src/bin/main.rs b/src/bin/main.rs index ad797c0..1e55016 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -301,7 +301,6 @@ fn main() { item::unit::Unit { unit: item::unit::UnitType::PriestMind, modifier: Some(item::unit::UnitModifier::Minus), - armor_slot: 0, // TODO: get rid of this } ), location: ItemLocation::Inventory { @@ -315,7 +314,6 @@ fn main() { item::unit::Unit { unit: item::unit::UnitType::PriestMind, modifier: Some(item::unit::UnitModifier::Minus), - armor_slot: 1, } ), location: ItemLocation::Inventory { @@ -329,7 +327,6 @@ fn main() { item::unit::Unit { unit: item::unit::UnitType::PriestMind, modifier: Some(item::unit::UnitModifier::Minus), - armor_slot: 2, } ), location: ItemLocation::Inventory { @@ -343,7 +340,6 @@ fn main() { item::unit::Unit { unit: item::unit::UnitType::PriestMind, modifier: Some(item::unit::UnitModifier::Minus), - armor_slot: 3, } ), location: ItemLocation::Inventory { @@ -373,6 +369,7 @@ fn main() { let inventory = item::InventoryEntity::new(vec![item0, item1, item2_w, item3, item4, item5_m, item6, item7_a, item8_s, item9_u0, item10_u1, item11_u2, item12_u3, item13]); entity_gateway.set_character_inventory(&character.id, &inventory).await.unwrap(); + entity_gateway.set_character_bank(&character.id, &item::BankEntity::default(), item::BankName("".into())).await.unwrap(); } info!("[patch] starting server"); diff --git a/src/entity/gateway/postgres/migrations/V0001__initial.sql b/src/entity/gateway/postgres/migrations/V0001__initial.sql index b4cd507..98e2f63 100644 --- a/src/entity/gateway/postgres/migrations/V0001__initial.sql +++ b/src/entity/gateway/postgres/migrations/V0001__initial.sql @@ -122,3 +122,27 @@ create table mag_modifier ( modifier jsonb not null, created_at timestamptz default current_timestamp not null ); + +create table equipped ( + pchar integer references player_character (id) unique not null, + weapon integer references item (id), + armor integer references item (id), + shield integer references item (id), + unit0 integer references item (id), + unit1 integer references item (id), + unit2 integer references item (id), + unit3 integer references item (id), + mag integer references item (id) +); + +create table inventory ( + pchar integer references player_character (id) unique not null, + items jsonb not null +); + +create table bank ( + pchar integer references player_character (id) not null, + items jsonb not null, + name varchar(128) not null, + unique (pchar, name) +); diff --git a/src/entity/gateway/postgres/models.rs b/src/entity/gateway/postgres/models.rs index 3f795a8..4b47a77 100644 --- a/src/entity/gateway/postgres/models.rs +++ b/src/entity/gateway/postgres/models.rs @@ -383,7 +383,6 @@ impl Into for PgShield { pub struct PgUnit { unit: unit::UnitType, modifier: Option, - //armor_slot: u8, } impl From for PgUnit { @@ -391,7 +390,6 @@ impl From for PgUnit { PgUnit { unit: other.unit, modifier: other.modifier, - //armor_slot: other.armor_slot, } } } @@ -401,7 +399,6 @@ impl Into for PgUnit { unit::Unit { unit: self.unit, modifier: self.modifier, - armor_slot: 0, } } } @@ -573,9 +570,6 @@ pub struct PgItem { pub enum PgItemLocationDetail { Inventory { character_id: u32, - //#[serde(skip_serializing)] - //slot: usize, - //equipped: bool, }, Bank { character_id: u32, @@ -676,6 +670,12 @@ pub struct PgMagModifier { } +#[derive(Debug, sqlx::FromRow)] +pub struct PgItemEntity { + pub id: i32, + pub item: sqlx::types::Json, +} + #[derive(Debug, sqlx::FromRow)] pub struct PgItemWithLocation { pub id: i32, @@ -683,6 +683,16 @@ pub struct PgItemWithLocation { pub location: sqlx::types::Json, } +impl Into for PgItemWithLocation { + fn into(self) -> ItemEntity { + ItemEntity { + id: ItemEntityId(self.id as u32), + item: self.item.0.into(), + location: self.location.0.into(), + } + } +} + #[derive(Debug, sqlx::FromRow)] pub struct PgMagModifierWithParameters { @@ -691,3 +701,70 @@ pub struct PgMagModifierWithParameters { pub feed: Option>, pub cell: Option>, } + + +#[derive(Debug, Serialize, Deserialize)] +#[serde(untagged)] +pub enum PgInventoryItemEntity { + Individual(i32), + Stacked(Vec), +} + +#[derive(Debug, sqlx::FromRow)] +pub struct PgInventoryEntity { + pub pchar: i32, + pub items: sqlx::types::Json>, +} + +#[derive(Debug, sqlx::FromRow)] +pub struct PgBankEntity { + pub pchar: i32, + pub items: sqlx::types::Json>, + pub name: String, +} + +#[derive(Debug, sqlx::FromRow)] +pub struct PgEquipped { + pchar: i32, + weapon: Option, + armor: Option, + shield: Option, + unit0: Option, + unit1: Option, + unit2: Option, + unit3: Option, + mag: Option, +} + +impl Into for PgEquipped { + fn into(self) -> EquippedEntity { + EquippedEntity { + weapon: self.weapon.map(|i| ItemEntityId(i as u32)), + armor: self.armor.map(|i| ItemEntityId(i as u32)), + shield: self.shield.map(|i| ItemEntityId(i as u32)), + unit: [self.unit0.map(|i| ItemEntityId(i as u32)), + self.unit1.map(|i| ItemEntityId(i as u32)), + self.unit2.map(|i| ItemEntityId(i as u32)), + self.unit3.map(|i| ItemEntityId(i as u32)), + ], + mag: self.mag.map(|i| ItemEntityId(i as u32)), + } + } +} + +impl From<(CharacterEntityId, EquippedEntity)> for PgEquipped { + fn from(char_equips: (CharacterEntityId, EquippedEntity)) -> PgEquipped { + PgEquipped { + pchar: char_equips.0.0 as i32, + weapon: char_equips.1.weapon.map(|i| i.0 as i32), + armor: char_equips.1.armor.map(|i| i.0 as i32), + shield: char_equips.1.shield.map(|i| i.0 as i32), + unit0: char_equips.1.unit[0].map(|i| i.0 as i32), + unit1: char_equips.1.unit[1].map(|i| i.0 as i32), + unit2: char_equips.1.unit[2].map(|i| i.0 as i32), + unit3: char_equips.1.unit[3].map(|i| i.0 as i32), + mag: char_equips.1.mag.map(|i| i.0 as i32), + } + } +} + diff --git a/src/entity/gateway/postgres/postgres.rs b/src/entity/gateway/postgres/postgres.rs index a999c94..0add18b 100644 --- a/src/entity/gateway/postgres/postgres.rs +++ b/src/entity/gateway/postgres/postgres.rs @@ -272,7 +272,22 @@ impl EntityGateway for PostgresGateway { } async fn create_item(&mut self, item: NewItemEntity) -> Result { - unimplemented!(); + let mut tx = self.pool.begin().await?; + let new_item = sqlx::query_as::<_, PgItem>("insert into item (item) values ($1) returning *;") + .bind(sqlx::types::Json(PgItemDetail::from(item.item))) + .fetch_one(&mut tx).await?; + let location = sqlx::query_as::<_, PgItemLocation>("insert into item_location (item, location) values ($1, $2) returning *") + .bind(new_item.id) + .bind(sqlx::types::Json(PgItemLocationDetail::from(item.location))) + .fetch_one(&mut tx).await?; + + tx.commit().await?; + Ok(ItemEntity { + id: ItemEntityId(new_item.id as u32), + item: new_item.item.0.into(), + location: location.location.0.into(), + }) + /* let mut tx = self.pool.begin().await?; let new_item = sqlx::query_as::<_, PgItem>("insert into item (item) values ($1) returning *;") @@ -324,7 +339,12 @@ impl EntityGateway for PostgresGateway { } async fn change_item_location(&mut self, item_id: &ItemEntityId, item_location: ItemLocation) -> Result<(), GatewayError> { - unimplemented!(); + sqlx::query("insert into item_location (item, location) values ($1, $2)") + .bind(item_id.0) + .bind(sqlx::types::Json(PgItemLocationDetail::from(item_location))) + .execute(&self.pool).await?; + Ok(()) + /* let mut tx = self.pool.begin().await?; if let ItemLocation::Inventory{slot, ..} = &item_location { @@ -417,27 +437,137 @@ impl EntityGateway for PostgresGateway { ).await) } */ - async fn get_character_inventory(&mut self, _char_id: &CharacterEntityId) -> Result { - unimplemented!(); + async fn get_character_inventory(&mut self, char_id: &CharacterEntityId) -> Result { + let inventory = sqlx::query_as::<_, PgInventoryEntity>("select * from inventory where pchar = $1") + .bind(char_id.0) + .fetch_one(&self.pool).await?; + // TODO: inefficient + let mut real_inventory = Vec::new(); + for inv_item in inventory.items.0.into_iter() { + match inv_item { + PgInventoryItemEntity::Individual(item) => { + let entity = sqlx::query_as::<_, PgItemWithLocation>("select item.id, item.item, item_location.location from item join item_location on item.id = item_location.item where id = $1") + .bind(item) + .fetch_one(&self.pool).await + .map(|item| item.into())?; + real_inventory.push(InventoryItemEntity::Individual(entity)); + }, + PgInventoryItemEntity::Stacked(items) => { + let mut stacked_item = Vec::new(); + for s_item in items { + stacked_item.push(sqlx::query_as::<_, PgItemWithLocation>("select item.id, item.item, item_location.location from item join item_location on item.id = item_location.item where id = $1") + .bind(s_item) + .fetch_one(&self.pool).await + .map(|item| item.into())?) + } + real_inventory.push(InventoryItemEntity::Stacked(stacked_item)); + } + } + } + + Ok(InventoryEntity::new(real_inventory)) } - async fn get_character_bank(&mut self, _char_id: &CharacterEntityId, _bank_name: BankName) -> Result { - unimplemented!(); + async fn get_character_bank(&mut self, char_id: &CharacterEntityId, bank_name: BankName) -> Result { + let bank = sqlx::query_as::<_, PgInventoryEntity>("select * from bank where pchar = $1 and name = $2") + .bind(char_id.0) + .bind(bank_name.0) + .fetch_one(&self.pool).await?; + // TODO: inefficient + let mut real_bank = Vec::new(); + for bank_item in bank.items.0.into_iter() { + match bank_item { + PgInventoryItemEntity::Individual(item) => { + let entity = sqlx::query_as::<_, PgItemWithLocation>("select item.id, item.item, item_location.location from item join item_location on item.id = item_location.item where id = $1") + .bind(item) + .fetch_one(&self.pool).await + .map(|item| item.into())?; + real_bank.push(BankItemEntity::Individual(entity)); + }, + PgInventoryItemEntity::Stacked(items) => { + let mut stacked_item = Vec::new(); + for s_item in items { + stacked_item.push(sqlx::query_as::<_, PgItemWithLocation>("select item.id, item.item, item_location.location from item join item_location on item.id = item_location.item where id = $1") + .bind(s_item) + .fetch_one(&self.pool).await + .map(|item| item.into())?) + } + real_bank.push(BankItemEntity::Stacked(stacked_item)); + } + } + } + + Ok(BankEntity::new(real_bank)) } - async fn set_character_inventory(&mut self, _char_id: &CharacterEntityId, _inventory: &InventoryEntity) -> Result<(), GatewayError> { - unimplemented!(); + async fn set_character_inventory(&mut self, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError> { + let inventory = inventory.items.iter() + .map(|item| { + match item { + InventoryItemEntity::Individual(item) => { + PgInventoryItemEntity::Individual(item.id.0 as i32) + }, + InventoryItemEntity::Stacked(items) => { + PgInventoryItemEntity::Stacked(items.iter().map(|i| i.id.0 as i32).collect()) + }, + } + }) + .collect::>(); + + sqlx::query("insert into inventory (pchar, items) values ($1, $2) on conflict (pchar) do update set items = $2") + .bind(char_id.0) + .bind(sqlx::types::Json(inventory)) + .execute(&self.pool) + .await?; + Ok(()) } - async fn set_character_bank(&mut self, _char_id: &CharacterEntityId, _inventory: &BankEntity, _bank_name: BankName) -> Result<(), GatewayError> { - unimplemented!(); + async fn set_character_bank(&mut self, char_id: &CharacterEntityId, bank: &BankEntity, bank_name: BankName) -> Result<(), GatewayError> { + let bank = bank.items.iter() + .map(|item| { + match item { + BankItemEntity::Individual(item) => { + PgInventoryItemEntity::Individual(item.id.0 as i32) + }, + BankItemEntity::Stacked(items) => { + PgInventoryItemEntity::Stacked(items.iter().map(|i| i.id.0 as i32).collect()) + }, + } + }) + .collect::>(); + + sqlx::query("insert into bank (pchar, items, name) values ($1, $2, $3) on conflict (pchar, name) do update set items = $2") + .bind(char_id.0) + .bind(sqlx::types::Json(bank)) + .bind(bank_name.0) + .execute(&self.pool) + .await?; + Ok(()) } - async fn get_character_equips(&mut self, _char_id: &CharacterEntityId) -> Result { - unimplemented!(); + async fn get_character_equips(&mut self, char_id: &CharacterEntityId) -> Result { + let equips = sqlx::query_as::<_, PgEquipped>("select * from equipped where pchar = $1") + .bind(char_id.0) + .fetch_one(&self.pool) + .await?; + + Ok(equips.into()) } - async fn set_character_equips(&mut self, _char_id: &CharacterEntityId, _equips: &EquippedEntity) -> Result<(), GatewayError> { - unimplemented!(); + async fn set_character_equips(&mut self, char_id: &CharacterEntityId, equips: &EquippedEntity) -> Result<(), GatewayError> { + sqlx::query(r#"insert into equipped (pchar, weapon, armor, shield, unit0, unit1, unit2, unit3, mag) values ($1, $2, $3, $4, $5, $6, $7, $8, $9) + on conflict (pchar) do update set weapon=$2, armor=$3, shield=$4, unit0=$5, unit1=$6, unit2=$7, unit3=$8, mag=$9"#) + .bind(char_id.0) + .bind(equips.weapon.map(|i| i.0 as i32)) + .bind(equips.armor.map(|i| i.0 as i32)) + .bind(equips.shield.map(|i| i.0 as i32)) + .bind(equips.unit[0].map(|i| i.0 as i32)) + .bind(equips.unit[1].map(|i| i.0 as i32)) + .bind(equips.unit[2].map(|i| i.0 as i32)) + .bind(equips.unit[3].map(|i| i.0 as i32)) + .bind(equips.mag.map(|i| i.0 as i32)) + .execute(&self.pool) + .await?; + Ok(()) } } diff --git a/src/entity/item/unit.rs b/src/entity/item/unit.rs index e7731fc..1f9dd4c 100644 --- a/src/entity/item/unit.rs +++ b/src/entity/item/unit.rs @@ -335,7 +335,6 @@ pub enum UnitModifier { pub struct Unit { pub unit: UnitType, pub modifier: Option, - pub armor_slot: u8, } @@ -362,7 +361,6 @@ impl Unit { }, } } - result[4] = self.armor_slot; result } @@ -380,7 +378,6 @@ impl Unit { Ok(Unit{ unit: u.unwrap(), modifier: m, - armor_slot: data[4], }) } else { diff --git a/src/ship/drops/generic_unit.rs b/src/ship/drops/generic_unit.rs index 9ba7e65..73bc4a6 100644 --- a/src/ship/drops/generic_unit.rs +++ b/src/ship/drops/generic_unit.rs @@ -89,7 +89,6 @@ impl GenericUnitTable { ItemDropType::Unit(Unit { unit: unit_type, modifier: unit_modifier, - armor_slot: 0, }) }) } @@ -117,7 +116,6 @@ mod test { assert!(gut.get_drop(&area, &mut rng) == Some(ItemDropType::Unit(Unit { unit: unit, modifier: umod, - armor_slot: 0, }))); } } diff --git a/src/ship/drops/rare_drop_table.rs b/src/ship/drops/rare_drop_table.rs index 9e08e7c..d4bfe03 100644 --- a/src/ship/drops/rare_drop_table.rs +++ b/src/ship/drops/rare_drop_table.rs @@ -128,7 +128,6 @@ impl RareDropTable { ItemDropType::Unit(Unit { unit: unit, modifier: None, - armor_slot: 0, }) }, RareDropItem::Tool(tool) => { diff --git a/src/ship/items/inventory.rs b/src/ship/items/inventory.rs index d915c98..68be036 100644 --- a/src/ship/items/inventory.rs +++ b/src/ship/items/inventory.rs @@ -14,12 +14,12 @@ const INVENTORY_CAPACITY: usize = 30; #[derive(Debug, Clone)] pub struct InventorySlot(pub usize); + #[derive(Debug, Clone)] pub struct IndividualInventoryItem { pub entity_id: ItemEntityId, pub item_id: ClientItemId, pub item: ItemDetail, - pub equipped: bool, } impl IndividualInventoryItem { @@ -154,17 +154,6 @@ impl InventoryItem { } } - pub fn equipped(&self) -> bool { - match self { - InventoryItem::Individual(individual_inventory_item) => { - individual_inventory_item.equipped - }, - InventoryItem::Stacked(_) => { - false - } - } - } - pub fn as_client_bytes(&self) -> [u8; 16] { match self { InventoryItem::Individual(item) => { @@ -353,13 +342,15 @@ impl<'a> InventoryItemHandle<'a> { pub struct CharacterInventory { item_id_counter: u32, items: Vec, + equipped: EquippedEntity, } impl CharacterInventory { - pub fn new(items: Vec) -> CharacterInventory { + pub fn new(items: Vec, equipped: &EquippedEntity) -> CharacterInventory { CharacterInventory{ item_id_counter: 0, items: items, + equipped: equipped.clone(), } } @@ -378,10 +369,22 @@ impl CharacterInventory { 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; - // does this do anything? - inventory[slot].equipped = if item.equipped() { 1 } else { 0 }; - // because this actually equips the item - inventory[slot].flags |= if item.equipped() { 8 } else { 0 }; + inventory[slot].equipped = 0; + inventory[slot].flags = 0; + + if let InventoryItem::Individual(individual_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, b)| a) + .unwrap_or(0) as u8 + } + inventory[slot].equipped = 1; + inventory[slot].flags |= 8; + } + } inventory }) } @@ -413,7 +416,7 @@ impl CharacterInventory { .filter(|(_, item)| { if let InventoryItem::Individual(individual_inventory_item) = item { if let ItemDetail::Mag(_) = &individual_inventory_item.item { - return individual_inventory_item.equipped + return self.equipped.is_equipped(&individual_inventory_item.entity_id) } } false @@ -431,7 +434,7 @@ impl CharacterInventory { .filter(|(_, item)| { if let InventoryItem::Individual(individual_inventory_item) = item { if let ItemDetail::Armor(_) = &individual_inventory_item.item { - return individual_inventory_item.equipped + return self.equipped.is_equipped(&individual_inventory_item.entity_id) } } false @@ -449,7 +452,7 @@ impl CharacterInventory { .filter(|(_, item)| { if let InventoryItem::Individual(individual_inventory_item) = item { if let ItemDetail::Shield(_) = &individual_inventory_item.item { - return individual_inventory_item.equipped + return self.equipped.is_equipped(&individual_inventory_item.entity_id) } } false @@ -467,7 +470,7 @@ impl CharacterInventory { .filter(|(_, item)| { if let InventoryItem::Individual(individual_inventory_item) = item { if let ItemDetail::Weapon(_) = &individual_inventory_item.item { - return individual_inventory_item.equipped + return self.equipped.is_equipped(&individual_inventory_item.entity_id) } } false @@ -509,7 +512,6 @@ impl CharacterInventory { entity_id: floor_item.entity_id, item_id: floor_item.item_id, item: floor_item.item.clone(), - equipped: false, })); if let Some(InventoryItem::Individual(new_item)) = self.items.last() { @@ -573,7 +575,6 @@ impl CharacterInventory { entity_id: individual_bank_item.entity_id, item_id: individual_bank_item.item_id, item: individual_bank_item.item.clone(), - equipped: false, })); (true, self.count()-1) }, @@ -582,7 +583,7 @@ impl CharacterInventory { .enumerate() .find_map(|(index, item)| { if let InventoryItem::Stacked(stacked_inventory_item) = item { - if stacked_inventory_item.tool == stacked_inventory_item.tool { + if stacked_bank_item.tool == stacked_inventory_item.tool { return Some((index, stacked_inventory_item)) } } @@ -639,6 +640,53 @@ impl CharacterInventory { self.items = sorted_items; } + pub fn equip(&mut self, id: &ClientItemId, equip_slot: u8) { + for item in &self.items { + if let InventoryItem::Individual(inventory_item) = item { + if inventory_item.item_id == *id { + match inventory_item.item { + ItemDetail::Weapon(_) => self.equipped.weapon = Some(inventory_item.entity_id), + ItemDetail::Armor(_) => self.equipped.armor = Some(inventory_item.entity_id), + ItemDetail::Shield(_) => self.equipped.shield = Some(inventory_item.entity_id), + ItemDetail::Unit(_) => { + if let Some(unit) = self.equipped.unit.get_mut(equip_slot as usize) { + *unit = Some(inventory_item.entity_id) + } + } + ItemDetail::Mag(_) => self.equipped.mag = Some(inventory_item.entity_id), + _ => {} + } + } + } + } + } + + pub fn unequip(&mut self, id: &ClientItemId) { + for item in &self.items { + if let InventoryItem::Individual(inventory_item) = item { + if inventory_item.item_id == *id { + match inventory_item.item { + ItemDetail::Weapon(_) => self.equipped.weapon = None, + ItemDetail::Armor(_) => { + self.equipped.armor = None; + self.equipped.unit = [None; 4]; + } + ItemDetail::Shield(_) => self.equipped.shield = None, + ItemDetail::Unit(_) => { + for unit in self.equipped.unit.iter_mut() { + if *unit == Some(inventory_item.entity_id) { + *unit = None + } + } + } + ItemDetail::Mag(_) => self.equipped.mag = Some(inventory_item.entity_id), + _ => {} + } + } + } + } + } + pub fn as_inventory_entity(&self, character_id: &CharacterEntityId) -> InventoryEntity { InventoryEntity { items: self.items.iter() @@ -673,25 +721,7 @@ impl CharacterInventory { } pub fn as_equipped_entity(&self) -> EquippedEntity { - self.items.iter() - .fold((EquippedEntity::default(), 0), |(mut equipped, mut unit_slot), item| { - if let InventoryItem::Individual(individual_item) = item { - if individual_item.equipped { - match individual_item.item { - ItemDetail::Weapon(_) => equipped.weapon = Some(individual_item.entity_id), - ItemDetail::Armor(_) => equipped.armor = Some(individual_item.entity_id), - ItemDetail::Shield(_) => equipped.shield = Some(individual_item.entity_id), - ItemDetail::Unit(_) => { - equipped.unit[unit_slot] = Some(individual_item.entity_id); - unit_slot += 1; - } - ItemDetail::Mag(_) => equipped.mag = Some(individual_item.entity_id), - _ => {}, - } - } - } - (equipped, unit_slot) - }).0 + self.equipped.clone() } } diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index fc84aa4..3a76284 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -97,7 +97,6 @@ impl ItemManager { entity_id: item.id, item_id: self.next_global_item_id(), item: item.item, - equipped: equipped.is_equipped(&item.id), }) }, InventoryItemEntity::Stacked(items) => { @@ -115,7 +114,7 @@ impl ItemManager { }) }) .collect::, _>>()?; - let character_inventory = CharacterInventory::new(inventory_items); + let character_inventory = CharacterInventory::new(inventory_items, &equipped); let bank_items = bank.items.into_iter() .map(|item| -> Result { @@ -147,102 +146,6 @@ impl ItemManager { self.character_inventory.insert(character.id, character_inventory); self.character_bank.insert(character.id, character_bank); Ok(()) - - /* - let items = entity_gateway.get_items_by_character(&character.id).await?; - let inventory_items = items.clone().into_iter() - .filter_map(|item| { - match item.location { - ItemLocation::Inventory{slot, equipped, ..} => Some((item.id, item.item, slot, equipped)), - _ => None, - } - }) - .fold(BTreeMap::new(), |mut acc, (id, item, slot, equipped)| { - if item.is_stackable() { - if let ItemDetail::Tool(tool) = item { - let inventory_item = acc.entry(slot).or_insert(InventoryItem::Stacked(StackedInventoryItem { - entity_ids: Vec::new(), - item_id: self.next_global_item_id(), - tool: tool, - })); - if let InventoryItem::Stacked(ref mut stacked_inventory_item) = inventory_item { - stacked_inventory_item.entity_ids.push(id); - } - } - } - else { - acc.insert(slot, InventoryItem::Individual(IndividualInventoryItem { - entity_id: id, - item_id: self.next_global_item_id(), - item: item, - equipped: equipped, - })); - } - - acc - }); - - // TODO: not using BankName anymore, clean this up - let mut bank_items = items.into_iter() - .filter_map(|item| { - match item.location { - ItemLocation::Bank{name, ..} => Some((item.id, item.item, name)), - _ => None, - } - }) - .fold(BTreeMap::new(), |mut acc, (id, item, name)| { - acc.entry(name).or_insert(Vec::new()).push((id, item)); - acc - }) - .into_iter() - .map(|(bank_name, bank_items)| { - let stacked_bank_items = bank_items.into_iter() - .fold(Vec::new(), |mut acc, (id, bank_item)| { - if bank_item.is_stackable() { - let existing_item = acc.iter_mut() - .find(|item| { - if let (BankItem::Stacked(stacked_bank_item), &ItemDetail::Tool(ref tool)) = (item, &bank_item) { - stacked_bank_item.tool == *tool - } - else { - false - } - }); - match existing_item { - Some(item) => { - if let BankItem::Stacked(ref mut stacked_bank_item) = item { - stacked_bank_item.entity_ids.push(id); - } - } - None => { - if let ItemDetail::Tool(tool) = bank_item { - acc.push(BankItem::Stacked(StackedBankItem { - entity_ids: vec![id], - item_id: self.next_global_item_id(), - tool: tool, - })); - } - }, - } - } - else { - acc.push(BankItem::Individual(IndividualBankItem { - entity_id: id, - item_id: self.next_global_item_id(), - item: bank_item, - })); - } - - acc - }); - (bank_name, CharacterBank::new(stacked_bank_items)) - }) - .collect::>(); - let inventory = CharacterInventory::new(inventory_items.into_iter().map(|(_k, v)| v).take(30).collect()); - self.character_inventory.insert(character.id, inventory); - self.character_bank.insert(character.id, bank_items.remove(&BankName("".to_string())).unwrap_or(CharacterBank::new(Vec::new()))); - Ok(()) - */ } pub fn add_character_to_room(&mut self, room_id: RoomId, character: &CharacterEntity, area_client: AreaClient) { @@ -941,10 +844,7 @@ impl ItemManager { equip_slot: u8) -> Result<(), ItemManagerError> { let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let mut inventory_item_handle = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - let slot = inventory_item_handle.get_slot(); - let inventory_item = inventory_item_handle.item_mut().ok_or(ItemManagerError::CannotGetMutItem)?.individual().ok_or(ItemManagerError::CannotGetIndividualItem)?; - inventory_item.equipped = true; + inventory.equip(&item_id, equip_slot); entity_gateway.set_character_equips(&character.id, &inventory.as_equipped_entity()).await?; Ok(()) } @@ -955,10 +855,7 @@ impl ItemManager { item_id: ClientItemId) -> Result<(), ItemManagerError> { let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let mut inventory_item_handle = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - let slot = inventory_item_handle.get_slot(); - let inventory_item = inventory_item_handle.item_mut().ok_or(ItemManagerError::CannotGetMutItem)?.individual().ok_or(ItemManagerError::CannotGetIndividualItem)?; - inventory_item.equipped = false; + inventory.unequip(&item_id); entity_gateway.set_character_equips(&character.id, &inventory.as_equipped_entity()).await?; Ok(()) } diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs index 28a8370..0bfc4ac 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -316,7 +316,8 @@ where EG: EntityGateway { let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - item_manager.player_equips_item(entity_gateway, &client.character, ClientItemId(pkt.item_id), pkt.sub_menu).await?; + let equip_slot = ((pkt.sub_menu & 0x7) - 1) % 4; + item_manager.player_equips_item(entity_gateway, &client.character, ClientItemId(pkt.item_id), equip_slot).await?; Ok(Box::new(None.into_iter())) } @@ -330,30 +331,7 @@ where EG: EntityGateway { let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - let equipped_unit_ids: Vec = { - item_manager.player_unequips_item(entity_gateway, &client.character, ClientItemId(pkt.item_id)).await?; - let inventory = item_manager.get_character_inventory(&client.character).unwrap(); - let ue_item = inventory.get_item_by_id(ClientItemId(pkt.item_id)).ok_or(ShipError::ItemError)?; - if let ItemType::Armor(_) = ue_item.item_type() { - inventory.items() - .iter() - .filter(|inv_item| { - if let ItemType::Unit(_) = inv_item.item_type() { - return inv_item.equipped() - } - false - }) - .map(|u| u.item_id()) - .collect() - } else { - Vec::new() - } - }; - - for unit_id in equipped_unit_ids { - item_manager.player_unequips_item(entity_gateway, &client.character, unit_id).await?; - } - + item_manager.player_unequips_item(entity_gateway, &client.character, ClientItemId(pkt.item_id)).await?; Ok(Box::new(None.into_iter())) } diff --git a/src/ship/shops/armor.rs b/src/ship/shops/armor.rs index 8920fcb..4ba1291 100644 --- a/src/ship/shops/armor.rs +++ b/src/ship/shops/armor.rs @@ -85,7 +85,6 @@ impl ShopItem for ArmorShopItem { ItemDetail::Unit(Unit { unit: *unit, modifier: None, - armor_slot: 0, }) }, } diff --git a/tests/test_item_actions.rs b/tests/test_item_actions.rs index f50a91b..a51e305 100644 --- a/tests/test_item_actions.rs +++ b/tests/test_item_actions.rs @@ -38,7 +38,6 @@ async fn test_equip_unit_from_equip_menu() { item::unit::Unit{ unit: item::unit::UnitType::KnightPower, modifier: None, - armor_slot: 0, }), location: item::ItemLocation::Inventory { character_id: char1.id, @@ -51,7 +50,6 @@ async fn test_equip_unit_from_equip_menu() { item::unit::Unit{ unit: item::unit::UnitType::KnightPower, modifier: Some(item::unit::UnitModifier::Plus), - armor_slot: 0, }), location: item::ItemLocation::Inventory { character_id: char1.id, @@ -127,7 +125,6 @@ async fn test_unequip_armor_with_units() { item::unit::Unit{ unit: item::unit::UnitType::KnightPower, modifier: None, - armor_slot: 0, }), location: item::ItemLocation::Inventory { character_id: char1.id, @@ -140,7 +137,6 @@ async fn test_unequip_armor_with_units() { item::unit::Unit{ unit: item::unit::UnitType::KnightPower, modifier: Some(item::unit::UnitModifier::Plus), - armor_slot: 1, }), location: item::ItemLocation::Inventory { character_id: char1.id, @@ -207,7 +203,6 @@ async fn test_sort_items() { item::unit::Unit{ unit: item::unit::UnitType::KnightPower, modifier: None, - armor_slot: 0, }), location: item::ItemLocation::Inventory { character_id: char1.id, @@ -220,7 +215,6 @@ async fn test_sort_items() { item::unit::Unit{ unit: item::unit::UnitType::KnightPower, modifier: Some(item::unit::UnitModifier::Plus), - armor_slot: 0, }), location: item::ItemLocation::Inventory { character_id: char1.id,