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