From eb0689a1fe99acee67a10270c9c31b58f8a8d53c Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 18 Jul 2022 20:51:35 -0600 Subject: [PATCH] enemy drop refactor --- src/ship/items/actions.rs | 138 +++++++++++++++++++++- src/ship/items/state.rs | 7 +- src/ship/packet/builder/message.rs | 12 +- src/ship/packet/handler/direct_message.rs | 14 +-- src/ship/ship.rs | 4 +- 5 files changed, 158 insertions(+), 17 deletions(-) diff --git a/src/ship/items/actions.rs b/src/ship/items/actions.rs index 544e17a..bd9544a 100644 --- a/src/ship/items/actions.rs +++ b/src/ship/items/actions.rs @@ -10,9 +10,11 @@ use crate::ship::items::state::{ItemState, ItemStateProxy, ItemStateAction, Item StackedItemDetail, BankItem, BankItemDetail, InventoryItemDetail, IndividualItemDetail}; use crate::ship::items::apply_item::apply_item; use crate::entity::item::{ItemDetail, NewItemEntity, TradeId}; +use crate::entity::item::tool::Tool; use crate::ship::shops::ShopItem; use crate::ship::trade::TradeItem; use crate::ship::location::{AreaClient, RoomId}; +use crate::ship::drops::{ItemDrop, ItemDropType}; pub enum TriggerCreateItem { Yes, @@ -239,7 +241,7 @@ fn add_meseta_to_shared_floor(character_id: CharacterEntityId, amount: u32, map_ }; let mut floor = item_state.floor(&character_id)?; - let floor_item = floor.add_item(floor_item).clone(); + let floor_item = floor.add_shared_item(floor_item).clone(); item_state.set_floor(floor); Ok(((item_state, transaction), floor_item)) @@ -1145,3 +1147,137 @@ where Ok((transaction, ())) }).await } + +fn convert_item_drop_to_floor_item(character_id: CharacterEntityId, item_drop: ItemDrop) + -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) + -> Pin, Box), FloorItem), ItemStateError>> + Send + 'a>> + Clone +{ + move |(mut item_state, mut transaction), _| { + let item_drop = item_drop.clone(); + Box::pin(async move { + enum ItemOrMeseta { + Individual(ItemDetail), + Stacked(Tool), + Meseta(Meseta) + } + + let item = match item_drop.item { + ItemDropType::Weapon(w) => ItemOrMeseta::Individual(ItemDetail::Weapon(w)), + ItemDropType::Armor(w) => ItemOrMeseta::Individual(ItemDetail::Armor(w)), + ItemDropType::Shield(w) => ItemOrMeseta::Individual(ItemDetail::Shield(w)), + ItemDropType::Unit(w) => ItemOrMeseta::Individual(ItemDetail::Unit(w)), + ItemDropType::TechniqueDisk(w) => ItemOrMeseta::Individual(ItemDetail::TechniqueDisk(w)), + ItemDropType::Mag(w) => ItemOrMeseta::Individual(ItemDetail::Mag(w)), + ItemDropType::Tool(t) => { + if t.tool.is_stackable() { + ItemOrMeseta::Stacked(t) + } + else { + ItemOrMeseta::Individual(ItemDetail::Tool(t)) + } + }, + ItemDropType::Meseta(m) => ItemOrMeseta::Meseta(Meseta(m)), + }; + + let item_id = item_state.new_item_id()?; + + let floor_item = match item { + ItemOrMeseta::Individual(item_detail) => { + let entity = transaction.gateway().create_item(NewItemEntity { + item: item_detail.clone(), + }).await?; + transaction.gateway().add_item_note(&entity.id, ItemNote::EnemyDrop { + character_id, + map_area: item_drop.map_area, + x: item_drop.x, + y: item_drop.y, + z: item_drop.z, + }).await?; + FloorItem { + item_id, + item: FloorItemDetail::Individual(IndividualItemDetail { + entity_id: entity.id, + item: item_detail, + }), + map_area: item_drop.map_area, + x: item_drop.x, + y: item_drop.y, + z: item_drop.z, + } + }, + ItemOrMeseta::Stacked(tool) => { + let entity = transaction.gateway().create_item(NewItemEntity { + item: ItemDetail::Tool(tool), + }).await?; + transaction.gateway().add_item_note(&entity.id, ItemNote::EnemyDrop { + character_id, + map_area: item_drop.map_area, + x: item_drop.x, + y: item_drop.y, + z: item_drop.z, + }).await?; + FloorItem { + item_id, + item: FloorItemDetail::Stacked(StackedItemDetail{ + entity_ids: vec![entity.id], + tool, + }), + map_area: item_drop.map_area, + x: item_drop.x, + y: item_drop.y, + z: item_drop.z, + } + }, + ItemOrMeseta::Meseta(meseta) => { + FloorItem { + item_id, + item: FloorItemDetail::Meseta(meseta), + map_area: item_drop.map_area, + x: item_drop.x, + y: item_drop.y, + z: item_drop.z, + } + }, + }; + + Ok(((item_state, transaction), floor_item)) + }) + } +} + +fn add_item_to_local_floor(character_id: CharacterEntityId) + -> impl for<'a> Fn((ItemStateProxy<'a>, Box), FloorItem) + -> Pin, Box), FloorItem), ItemStateError>> + Send + 'a>> +{ + move |(mut item_state, transaction) , floor_item| { + Box::pin(async move { + let mut floor = item_state.floor(&character_id)?; + let item = floor.add_local_item(floor_item).clone(); + item_state.set_floor(floor); + + Ok(((item_state, transaction), item)) + }) + } +} + +pub async fn enemy_drops_item<'a, EG> ( + item_state: &'a mut ItemState, + entity_gateway: &mut EG, + character_id: CharacterEntityId, + item_drop: ItemDrop) + -> Result +where + EG: EntityGateway, +{ + entity_gateway.with_transaction(|mut transaction| async move { + let item_state_proxy = ItemStateProxy::new(item_state); + let ((item_state_proxy, transaction), floor_item) = ItemStateAction::default() + .act(convert_item_drop_to_floor_item(character_id, item_drop)) + .act(add_item_to_local_floor(character_id)) + .commit((item_state_proxy, transaction)) + .await?; + + item_state_proxy.commit(); + Ok((transaction, floor_item)) + }).await +} diff --git a/src/ship/items/state.rs b/src/ship/items/state.rs index 22ce757..0a69991 100644 --- a/src/ship/items/state.rs +++ b/src/ship/items/state.rs @@ -1214,10 +1214,15 @@ impl FloorState { &self.shared.0[self.shared.0.len()-1] } - pub fn add_item(&mut self, floor_item: FloorItem) -> &FloorItem { + pub fn add_shared_item(&mut self, floor_item: FloorItem) -> &FloorItem { self.shared.0.push(floor_item); &self.shared.0[self.shared.0.len()-1] } + + pub fn add_local_item(&mut self, floor_item: FloorItem) -> &FloorItem { + self.local.0.push(floor_item); + &self.local.0[self.local.0.len()-1] + } } diff --git a/src/ship/packet/builder/message.rs b/src/ship/packet/builder/message.rs index a349b8f..b149508 100644 --- a/src/ship/packet/builder/message.rs +++ b/src/ship/packet/builder/message.rs @@ -12,19 +12,19 @@ use std::convert::TryInto; use crate::ship::shops::ShopItem; -pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> Result { +pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem2) -> Result { let item_bytes = item_drop.as_client_bytes(); Ok(ItemDrop { client, target, - map_area: item_drop.map_area().area_value(), + map_area: item_drop.map_area.area_value(), variety: 0, unknown: 0, - x: item_drop.x(), - z: item_drop.z(), - y: item_drop.y(), + x: item_drop.x, + z: item_drop.z, + y: item_drop.y, item_bytes: item_bytes[0..12].try_into()?, - item_id: item_drop.item_id().0, + item_id: item_drop.item_id.0, item_bytes2: item_bytes[12..16].try_into()?, unknown2: 0, }) diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index 1cc319a..511f218 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -15,7 +15,7 @@ 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, withdraw_meseta, deposit_meseta, withdraw_item, deposit_item, buy_shop_item, TriggerCreateItem}; +use crate::ship::items::actions::{pick_up_item, withdraw_meseta, deposit_meseta, withdraw_item, deposit_item, buy_shop_item, enemy_drops_item, TriggerCreateItem}; const BANK_ACTION_DEPOSIT: u8 = 0; const BANK_ACTION_WITHDRAW: u8 = 1; @@ -76,7 +76,7 @@ pub async fn request_item(id: ClientId, client_location: &ClientLocation, clients: &mut Clients, rooms: &mut Rooms, - item_manager: &mut ItemManager) + item_state: &mut ItemState) -> Result + Send>, anyhow::Error> where EG: EntityGateway @@ -111,8 +111,8 @@ where item: item_drop, }; let client = clients.get_mut(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client))?; - let floor_item = item_manager.enemy_drop_item_on_local_floor(entity_gateway, &client.character, item_drop).await?; - let item_drop_msg = builder::message::item_drop(request_item.client, request_item.target, floor_item)?; + let floor_item = enemy_drops_item(item_state, entity_gateway, client.character.id, item_drop).await?; + let item_drop_msg = builder::message::item_drop(request_item.client, request_item.target, &floor_item)?; item_drop_packets.push((area_client.client, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(item_drop_msg))))); } @@ -195,7 +195,7 @@ pub async fn request_box_item(id: ClientId, client_location: &ClientLocation, clients: &mut Clients, rooms: &mut Rooms, - item_manager: &mut ItemManager) + item_state: &mut ItemState) -> Result + Send>, anyhow::Error> where EG: EntityGateway @@ -230,8 +230,8 @@ EG: EntityGateway item: item_drop, }; let client = clients.get_mut(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client))?; - let floor_item = item_manager.enemy_drop_item_on_local_floor(entity_gateway, &client.character, item_drop).await?; // TODO: unwrap - let item_drop_msg = builder::message::item_drop(box_drop_request.client, box_drop_request.target, floor_item)?; + let floor_item = enemy_drops_item(item_state, entity_gateway, client.character.id, item_drop).await?; + let item_drop_msg = builder::message::item_drop(box_drop_request.client, box_drop_request.target, &floor_item)?; item_drop_packets.push((area_client.client, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(item_drop_msg))))) } diff --git a/src/ship/ship.rs b/src/ship/ship.rs index e6ec80d..69d95fa 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -546,13 +546,13 @@ impl ShipServerState { handler::direct_message::guildcard_send(id, guildcard_send, target, &block.client_location, &self.clients) }, GameMessage::RequestItem(request_item) => { - handler::direct_message::request_item(id, request_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_manager).await? + handler::direct_message::request_item(id, request_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_state).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_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? + 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_state).await? }, GameMessage::BankRequest(_bank_request) => { handler::direct_message::send_bank_list(id, &self.clients, &mut self.item_state).await?