1use crate::client::Client;
2use common::{
3 comp::{ChatMode, ChatType, Content, Group, Player},
4 event::{self, EmitExt},
5 event_emitters,
6 resources::ProgramTime,
7 uid::Uid,
8};
9use common_ecs::{Job, Origin, Phase, System};
10use common_net::msg::{ClientGeneral, ServerGeneral};
11use rayon::prelude::*;
12use specs::{Entities, LendJoin, ParJoin, Read, ReadStorage, WriteStorage};
13use tracing::{debug, error, warn};
14
15event_emitters! {
16 struct Events[Emitters] {
17 command: event::CommandEvent,
18 client_disconnect: event::ClientDisconnectEvent,
19 chat: event::ChatEvent,
20
21 #[cfg(feature = "plugins")]
22 plugins: event::RequestPluginsEvent,
23 }
24}
25
26impl Sys {
27 fn handle_general_msg(
28 emitters: &mut Emitters,
29 entity: specs::Entity,
30 client: &Client,
31 player: Option<&Player>,
32 uids: &ReadStorage<'_, Uid>,
33 chat_modes: &ReadStorage<'_, ChatMode>,
34 groups: &ReadStorage<'_, Group>,
35 msg: ClientGeneral,
36 ) -> Result<(), crate::error::Error> {
37 match msg {
38 ClientGeneral::ChatMsg(message) => {
39 if !client.client_type.can_send_message() {
40 client.send_fallible(ServerGeneral::ChatMsg(
41 ChatType::CommandError
42 .into_msg(Content::localized("command-cannot-send-message-hidden")),
43 ));
44 } else if player.is_some() {
45 if let Some(from) = uids.get(entity) {
46 const CHAT_MODE_DEFAULT: &ChatMode = &ChatMode::default();
47 let mode = chat_modes.get(entity).unwrap_or(CHAT_MODE_DEFAULT);
48 match mode.to_msg(*from, message, groups.get(entity).copied()) {
50 Ok(message) => {
51 emitters.emit(event::ChatEvent {
52 msg: message,
53 from_client: true,
54 });
55 },
56 Err(error) => {
57 client.send_fallible(ServerGeneral::ChatMsg(
58 ChatType::CommandError.into_msg(error),
59 ));
60 },
61 }
62 } else {
63 error!("Could not send message. Missing player uid");
64 }
65 } else {
66 warn!("Received a chat message from an unregistered client");
67 }
68 },
69 ClientGeneral::Command(name, args) => {
70 if player.is_some() {
71 emitters.emit(event::CommandEvent(entity, name, args));
72 }
73 },
74 ClientGeneral::Terminate => {
75 debug!(?entity, "Client send message to terminate session");
76 emitters.emit(event::ClientDisconnectEvent(
77 entity,
78 common::comp::DisconnectReason::ClientRequested,
79 ));
80 },
81 ClientGeneral::RequestPlugins(plugins) => {
82 tracing::info!("Plugin request {plugins:x?}, {}", player.is_some());
83
84 #[cfg(feature = "plugins")]
85 emitters.emit(event::RequestPluginsEvent { entity, plugins });
86 },
87 _ => {
88 debug!("Kicking possible misbehaving client due to invalid message request");
89 emitters.emit(event::ClientDisconnectEvent(
90 entity,
91 common::comp::DisconnectReason::NetworkError,
92 ));
93 },
94 }
95 Ok(())
96 }
97}
98
99#[derive(Default)]
101pub struct Sys;
102impl<'a> System<'a> for Sys {
103 type SystemData = (
104 Entities<'a>,
105 Events<'a>,
106 Read<'a, ProgramTime>,
107 ReadStorage<'a, Uid>,
108 ReadStorage<'a, ChatMode>,
109 ReadStorage<'a, Player>,
110 ReadStorage<'a, Group>,
111 WriteStorage<'a, Client>,
112 );
113
114 const NAME: &'static str = "msg::general";
115 const ORIGIN: Origin = Origin::Server;
116 const PHASE: Phase = Phase::Create;
117
118 fn run(
119 _job: &mut Job<Self>,
120 (entities, events, program_time, uids, chat_modes, players, groups, mut clients): Self::SystemData,
121 ) {
122 (&entities, &mut clients, players.maybe())
123 .par_join()
124 .for_each_init(
125 || events.get_emitters(),
126 |emitters, (entity, client, player)| {
127 let res = super::try_recv_all(client, 3, |client, msg| {
128 Self::handle_general_msg(
129 emitters,
130 entity,
131 client,
132 player,
133 &uids,
134 &chat_modes,
135 &groups,
136 msg,
137 )
138 });
139
140 if let Ok(1_u64..=u64::MAX) = res {
141 client.last_ping = program_time.0
143 }
144 },
145 );
146 }
147}