use hashbrown::HashSet; use rand::{seq::IteratorRandom, Rng}; use specs::{join::Join, world::WorldExt, Builder, Entity as EcsEntity, WriteStorage}; use tracing::{debug, error, warn}; use vek::{Rgb, Vec3}; use common::{ comp::{ self, group::members, item::{self, flatten_counted_items, tool::AbilityMap, MaterialStatManifest}, loot_owner::LootOwnerKind, slot::{self, Slot}, InventoryUpdate, LootOwner, Stats, }, consts::MAX_PICKUP_RANGE, mounting::VolumePos, recipe::{ self, default_component_recipe_book, default_recipe_book, default_repair_recipe_book, }, resources::Time, terrain::{Block, SpriteKind}, trade::Trades, uid::Uid, util::find_dist::{self, FindDist}, vol::ReadVol, }; use common_net::sync::WorldSyncExt; use common_state::State; use comp::LightEmitter; use crate::{client::Client, Server, StateExt}; use common::{ comp::{ pet::is_tameable, Alignment, Body, CollectFailedReason, Group, InventoryUpdateEvent, Player, }, event::{EventBus, ServerEvent}, }; use common_net::msg::ServerGeneral; pub fn swap_lantern( storage: &mut WriteStorage, entity: EcsEntity, (lantern_color, lantern_strength): (Rgb, f32), ) { if let Some(mut light) = storage.get_mut(entity) { light.strength = lantern_strength; light.col = lantern_color; } } pub fn snuff_lantern(storage: &mut WriteStorage, entity: EcsEntity) { storage.remove(entity); } #[allow(clippy::blocks_in_if_conditions)] pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::InventoryManip) { let state = server.state_mut(); let uid = if let Some(uid) = state.ecs().uid_from_entity(entity) { uid } else { warn!( "Couldn't get uid for entity {:?} at start of handle_inventory", entity ); return; }; { let trades = state.ecs().read_resource::(); if trades.in_immutable_trade(&uid) { // manipulating the inventory can mutate the trade return; } } let mut dropped_items = Vec::new(); let mut thrown_items = Vec::new(); let get_cylinder = |state: &State, entity| { let ecs = state.ecs(); let positions = ecs.read_storage::(); let scales = ecs.read_storage::(); let colliders = ecs.read_storage::(); let char_states = ecs.read_storage::(); positions.get(entity).map(|p| { find_dist::Cylinder::from_components( p.0, scales.get(entity).copied(), colliders.get(entity), char_states.get(entity), ) }) }; let mut inventories = state.ecs().write_storage::(); let mut inventory = if let Some(inventory) = inventories.get_mut(entity) { inventory } else { error!( ?entity, "Can't manipulate inventory, entity doesn't have one" ); return; }; // Disallow inventory manipulation while dead if state .ecs() .read_storage::() .get(entity) .map_or(false, |h| h.is_dead) { debug!("Can't manipulate inventory; entity is dead"); return; } let time = *state.ecs().read_resource::