use log::warn; use libpso::packet::ship::*; use libpso::packet::messages::*; use crate::common::serverstate::ClientId; use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms}; use crate::ship::location::{ClientLocation, ClientLocationError}; use crate::ship::drops::{ItemDrop}; use crate::ship::items::ActiveItemDatabase; use crate::entity::gateway::EntityGateway; use libpso::{utf8_to_utf16_array}; use crate::ship::packet::builder; fn send_to_client(id: ClientId, target: u8, msg: DirectMessage, client_location: &ClientLocation) -> Box + Send> { Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter() .filter(move |client| client.local_client.id() == target) .map(move |client| { (client.client, SendShipPacket::DirectMessage(msg.clone())) })) } pub fn guildcard_send(id: ClientId, guildcard_send: &GuildcardSend, target: u32, client_location: &ClientLocation, clients: &Clients) -> Box + Send> { let client = clients.get(&id).unwrap(); let msg = DirectMessage{ flag: target, msg: GameMessage::GuildcardRecv(GuildcardRecv { client: guildcard_send.client, target: guildcard_send.target, guildcard: client.user.id.0, name: utf8_to_utf16_array!(client.character.name, 0x18), team: [0; 0x10], // TODO: teams not yet implemented desc: utf8_to_utf16_array!(client.character.guildcard.description, 0x58), one: 1, language: 0, // TODO: add language flag to character section_id: client.character.section_id.into(), class: client.character.char_class.into(), }), }; send_to_client(id, target as u8, msg, &client_location) } pub fn request_item(id: ClientId, request_item: &RequestItem, entity_gateway: &mut EG, client_location: &ClientLocation, clients: &mut Clients, rooms: &mut Rooms, active_items: &mut ActiveItemDatabase) -> Result + Send>, ShipError> where EG: EntityGateway { let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; let room = rooms.get_mut(room_id.0) .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))? .as_mut() .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?; let monster = room.maps.enemy_by_id(request_item.enemy_id as usize)?; if monster.dropped_item { return Err(ShipError::MonsterAlreadyDroppedItem(id, request_item.enemy_id)) } let _area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?; let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; let item_drop_packets = clients_in_area.into_iter() .filter_map(|area_client| { room.drop_table.get_drop(&monster.map_area, &monster.monster).map(|item_drop_type| { warn!("drop is? {:?}", item_drop_type); (area_client, item_drop_type) }) }) .map(|(area_client, item_drop_type)| -> Result<_, ShipError> { let item_drop = ItemDrop { map_area: monster.map_area, x: request_item.x, y: request_item.y, z: request_item.z, item: item_drop_type, }; let activated_item = active_items.activate_item_drop(entity_gateway, item_drop)?; let client = clients.get_mut(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client))?; let item_drop_msg = builder::message::item_drop(request_item.client, request_item.target, &activated_item)?; client.floor_items.push(activated_item); Ok((area_client.client, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(item_drop_msg))))) }) .filter_map(|item_drop_pkt| { // TODO: log errors here item_drop_pkt.ok() }) .collect::>(); // TODO: can EntityGateway be Sync? Ok(Box::new(item_drop_packets.into_iter())) }