use crate::{ automod::AutoMod, client::Client, events::{self, update_map_markers}, persistence::PersistedComponents, pet::restore_pet, presence::{Presence, RepositionOnChunkLoad}, settings::Settings, sys::sentinel::DeletedEntities, wiring, BattleModeBuffer, SpawnPoint, }; use common::{ calendar::Calendar, character::CharacterId, combat, combat::DamageContributor, comp::{ self, item::MaterialStatManifest, skills::{GeneralSkill, Skill}, ChatType, Group, Inventory, Item, Player, Poise, }, effect::Effect, link::{Link, LinkHandle}, mounting::Mounting, resources::{Time, TimeOfDay}, slowjob::SlowJobPool, uid::{Uid, UidAllocator}, ViewDistances, }; use common_net::{ msg::{CharacterInfo, PlayerListUpdate, PresenceKind, ServerGeneral}, sync::WorldSyncExt, }; use common_state::State; use rand::prelude::*; use specs::{ saveload::MarkerAllocator, Builder, Entity as EcsEntity, EntityBuilder as EcsEntityBuilder, Join, WorldExt, }; use std::time::{Duration, Instant}; use tracing::{trace, warn}; use vek::*; pub trait StateExt { /// Updates a component associated with the entity based on the `Effect` fn apply_effect(&self, entity: EcsEntity, effect: Effect, source: Option); /// Build a non-player character fn create_npc( &mut self, pos: comp::Pos, stats: comp::Stats, skill_set: comp::SkillSet, health: Option, poise: Poise, inventory: Inventory, body: comp::Body, ) -> EcsEntityBuilder; /// Build a static object entity fn create_object(&mut self, pos: comp::Pos, object: comp::object::Body) -> EcsEntityBuilder; fn create_item_drop(&mut self, pos: comp::Pos, item: Item) -> EcsEntityBuilder; fn create_ship comp::Collider>( &mut self, pos: comp::Pos, ship: comp::ship::Body, make_collider: F, mountable: bool, ) -> EcsEntityBuilder; /// Build a projectile fn create_projectile( &mut self, pos: comp::Pos, vel: comp::Vel, body: comp::Body, projectile: comp::Projectile, ) -> EcsEntityBuilder; /// Build a shockwave entity fn create_shockwave( &mut self, properties: comp::shockwave::Properties, pos: comp::Pos, ori: comp::Ori, ) -> EcsEntityBuilder; /// Build a beam entity fn create_beam( &mut self, properties: comp::beam::Properties, pos: comp::Pos, ori: comp::Ori, ) -> EcsEntityBuilder; /// Creates a safezone fn create_safezone(&mut self, range: Option, pos: comp::Pos) -> EcsEntityBuilder; fn create_wiring( &mut self, pos: comp::Pos, object: comp::object::Body, wiring_element: wiring::WiringElement, ) -> EcsEntityBuilder; // NOTE: currently only used for testing /// Queues chunk generation in the view distance of the persister, this /// entity must be built before those chunks are received (the builder /// borrows the ecs world so that is kind of impossible in practice) fn create_persister( &mut self, pos: comp::Pos, view_distance: u32, world: &std::sync::Arc, index: &world::IndexOwned, ) -> EcsEntityBuilder; /// Insert common/default components for a new character joining the server fn initialize_character_data( &mut self, entity: EcsEntity, character_id: CharacterId, view_distances: ViewDistances, ); /// Insert common/default components for a new spectator joining the server fn initialize_spectator_data(&mut self, entity: EcsEntity, view_distances: ViewDistances); /// Update the components associated with the entity's current character. /// Performed after loading component data from the database fn update_character_data(&mut self, entity: EcsEntity, components: PersistedComponents); /// Iterates over registered clients and send each `ServerMsg` fn validate_chat_msg( &self, player: EcsEntity, chat_type: &comp::ChatType, msg: &str, ) -> bool; fn send_chat(&self, msg: comp::UnresolvedChatMsg); fn notify_players(&self, msg: ServerGeneral); fn notify_in_game_clients(&self, msg: ServerGeneral); /// Create a new link between entities (see [`common::mounting`] for an /// example). fn link(&mut self, link: L) -> Result<(), L::Error>; /// Maintain active links between entities fn maintain_links(&mut self); /// Delete an entity, recording the deletion in [`DeletedEntities`] fn delete_entity_recorded( &mut self, entity: EcsEntity, ) -> Result<(), specs::error::WrongGeneration>; } impl StateExt for State { fn apply_effect(&self, entity: EcsEntity, effects: Effect, source: Option) { let msm = self.ecs().read_resource::(); match effects { Effect::Health(change) => { self.ecs() .write_storage::() .get_mut(entity) .map(|mut health| health.change_by(change)); }, Effect::Damage(damage) => { let inventories = self.ecs().read_storage::(); let stats = self.ecs().read_storage::(); let groups = self.ecs().read_storage::(); let damage_contributor = source.and_then(|uid| { self.ecs().entity_from_uid(uid.0).map(|attacker_entity| { DamageContributor::new(uid, groups.get(attacker_entity).cloned()) }) }); let time = self.ecs().read_resource::