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