veloren_server/events/
mod.rs

1use std::{marker::PhantomData, sync::Arc};
2
3use crate::{Server, state_ext::StateExt};
4use common::event::{
5    ChatEvent, ClientDisconnectEvent, ClientDisconnectWithoutPersistenceEvent, CommandEvent,
6    EventBus, ExitIngameEvent,
7};
8use common_base::span;
9use entity_creation::handle_summon_beam_pillars;
10use hashbrown::HashSet;
11use player::handle_set_battle_mode;
12use specs::{
13    DispatcherBuilder, Entity as EcsEntity, ReadExpect, WorldExt, WriteExpect,
14    shred::SendDispatcher,
15};
16
17use self::{
18    entity_creation::{
19        handle_create_aura_entity, handle_create_item_drop, handle_create_npc,
20        handle_create_object, handle_create_ship, handle_create_special_entity,
21        handle_initialize_character, handle_initialize_spectator, handle_loaded_character_data,
22        handle_shockwave, handle_shoot, handle_throw,
23    },
24    entity_manipulation::{handle_delete, handle_start_interaction, handle_transform},
25    interaction::handle_tame_pet,
26    mounting::handle_mount,
27    player::{
28        handle_character_delete, handle_client_disconnect, handle_exit_ingame, handle_possess,
29    },
30    trade::handle_process_trade_action,
31};
32
33mod entity_creation;
34mod entity_manipulation;
35mod event_types;
36mod group_manip;
37mod information;
38mod interaction;
39mod inventory_manip;
40mod invite;
41mod mounting;
42mod player;
43mod trade;
44
45pub(crate) use event_types::register_event_busses;
46/// Shared utilities used by other code **in this crate**
47pub(crate) mod shared {
48    pub(crate) use super::{
49        entity_manipulation::{TransformEntityError, transform_entity},
50        group_manip::update_map_markers,
51        trade::cancel_trades_for,
52    };
53}
54
55pub trait ServerEvent: Send + Sync + 'static {
56    type SystemData<'a>: specs::SystemData<'a>;
57
58    const NAME: &'static str = std::any::type_name::<Self>();
59
60    fn handle(events: impl ExactSizeIterator<Item = Self>, data: Self::SystemData<'_>);
61}
62
63struct EventHandler<T>(PhantomData<T>);
64impl<T> Default for EventHandler<T> {
65    fn default() -> Self { Self(PhantomData) }
66}
67
68impl<'a, T: ServerEvent> common_ecs::System<'a> for EventHandler<T> {
69    type SystemData = (
70        ReadExpect<'a, crate::metrics::ServerEventMetrics>,
71        WriteExpect<'a, EventBus<T>>,
72        T::SystemData<'a>,
73    );
74
75    const NAME: &'static str = T::NAME;
76    const ORIGIN: common_ecs::Origin = common_ecs::Origin::Server;
77    const PHASE: common_ecs::Phase = common_ecs::Phase::Apply;
78
79    fn run(_job: &mut common_ecs::Job<Self>, (metrics, mut ev, data): Self::SystemData) {
80        span!(guard, "Recv events");
81        let events = ev.recv_all_mut();
82        drop(guard);
83
84        span!(guard, "Add metrics for event");
85        metrics
86            .event_count
87            .with_label_values(&[T::NAME])
88            .inc_by(events.len() as u64);
89        drop(guard);
90
91        span!(guard, "Handle events");
92        T::handle(events, data);
93        drop(guard);
94    }
95}
96
97fn event_dispatch<T: ServerEvent>(builder: &mut DispatcherBuilder, dependencies: &[&str]) {
98    common_ecs::dispatch::<EventHandler<T>>(builder, dependencies);
99}
100
101fn event_sys_name<T: ServerEvent>() -> String {
102    <EventHandler<T> as common_ecs::System>::sys_name()
103}
104
105pub fn register_event_systems(builder: &mut DispatcherBuilder) {
106    inventory_manip::register_event_systems(builder);
107    entity_manipulation::register_event_systems(builder);
108    interaction::register_event_systems(builder);
109    invite::register_event_systems(builder);
110    group_manip::register_event_systems(builder);
111    information::register_event_systems(builder);
112}
113
114/// Server frontend events.
115///
116/// These events are returned to the frontend that ticks the server.
117pub enum Event {
118    ClientConnected {
119        entity: EcsEntity,
120    },
121    ClientDisconnected {
122        entity: EcsEntity,
123    },
124    Chat {
125        entity: Option<EcsEntity>,
126        msg: String,
127    },
128}
129
130impl Server {
131    fn handle_serial_events<T: Send + 'static, F: FnMut(&mut Self, T)>(&mut self, mut f: F) {
132        if let Some(bus) = self.state.ecs_mut().get_mut::<EventBus<T>>() {
133            let events = bus.recv_all_mut();
134            let server_event_metrics = self
135                .state
136                .ecs()
137                .read_resource::<crate::metrics::ServerEventMetrics>();
138            server_event_metrics
139                .event_count
140                .with_label_values(&[std::any::type_name::<T>()])
141                .inc_by(events.len() as u64);
142            drop(server_event_metrics);
143
144            for ev in events {
145                f(self, ev)
146            }
147        }
148    }
149
150    fn handle_all_serial_events(&mut self, frontend_events: &mut Vec<Event>) {
151        self.handle_serial_events(handle_initialize_character);
152        self.handle_serial_events(handle_initialize_spectator);
153        self.handle_serial_events(handle_loaded_character_data);
154        self.handle_serial_events(|this, ev| {
155            handle_create_npc(this, ev);
156        });
157        self.handle_serial_events(handle_create_ship);
158        self.handle_serial_events(handle_shoot);
159        self.handle_serial_events(handle_throw);
160        self.handle_serial_events(handle_shockwave);
161        self.handle_serial_events(handle_create_special_entity);
162        self.handle_serial_events(handle_create_item_drop);
163        self.handle_serial_events(handle_create_object);
164        self.handle_serial_events(handle_create_aura_entity);
165        self.handle_serial_events(handle_summon_beam_pillars);
166        self.handle_serial_events(handle_delete);
167
168        self.handle_serial_events(handle_character_delete);
169        self.handle_serial_events(|this, ev: ExitIngameEvent| {
170            handle_exit_ingame(this, ev.entity, false)
171        });
172        let mut already_disconnected_clients = HashSet::new();
173        self.handle_serial_events(|this, ev: ClientDisconnectEvent| {
174            if let Some(event) =
175                handle_client_disconnect(this, ev.0, ev.1, false, &mut already_disconnected_clients)
176            {
177                frontend_events.push(event);
178            }
179        });
180        self.handle_serial_events(|this, ev: ClientDisconnectWithoutPersistenceEvent| {
181            if let Some(event) = handle_client_disconnect(
182                this,
183                ev.0,
184                common::comp::DisconnectReason::Kicked,
185                true,
186                &mut already_disconnected_clients,
187            ) {
188                frontend_events.push(event);
189            }
190        });
191        self.handle_serial_events(handle_possess);
192        self.handle_serial_events(handle_transform);
193        self.handle_serial_events(handle_start_interaction);
194        self.handle_serial_events(|this, ev: CommandEvent| {
195            this.process_command(ev.0, ev.1, ev.2);
196        });
197        self.handle_serial_events(|this, ev: ChatEvent| {
198            this.state.send_chat(ev.msg, ev.from_client);
199        });
200        self.handle_serial_events(handle_mount);
201        self.handle_serial_events(handle_tame_pet);
202        self.handle_serial_events(handle_process_trade_action);
203        self.handle_serial_events(handle_set_battle_mode);
204    }
205
206    pub fn handle_events(&mut self) -> Vec<Event> {
207        let mut frontend_events = Vec::new();
208
209        span!(guard, "run event systems");
210        // This dispatches all the systems in parallel.
211        self.event_dispatcher.dispatch(self.state.ecs());
212        drop(guard);
213
214        span!(guard, "handle serial events");
215        self.handle_all_serial_events(&mut frontend_events);
216        drop(guard);
217
218        self.state.maintain_ecs();
219
220        #[cfg(debug_assertions)]
221        {
222            event_types::check_event_handlers(self.state.ecs_mut())
223        }
224
225        frontend_events
226    }
227
228    pub fn create_event_dispatcher(pools: Arc<rayon::ThreadPool>) -> SendDispatcher<'static> {
229        span!(_guard, "create event dispatcher");
230        // Run systems to handle events.
231        // Create and run a dispatcher for ecs systems.
232        let mut dispatch_builder = DispatcherBuilder::new().with_pool(pools);
233        register_event_systems(&mut dispatch_builder);
234        dispatch_builder
235            .build()
236            .try_into_sendable()
237            .ok()
238            .expect("This should be sendable")
239    }
240}