veloren_server/
client.rs

1use common_net::msg::{ClientType, ServerGeneral, ServerMsg};
2use network::{ConnectAddr, Message, Participant, Stream, StreamError, StreamParams};
3use serde::{Serialize, de::DeserializeOwned};
4use specs::Component;
5use std::{net::SocketAddr, sync::atomic::AtomicBool};
6
7/// Client handles ALL network related information of everything that connects
8/// to the server Client DOES NOT handle game states
9/// Client DOES NOT handle network information that is only relevant to some
10/// "things" connecting to the server (there is currently no such case). First a
11/// Client connects to the game, when it registers, it gets the `Player`
12/// component, when it enters the game it gets the `InGame` component.
13pub struct Client {
14    pub client_type: ClientType,
15    pub participant: Option<Participant>,
16    pub current_ip_addrs: Vec<SocketAddr>,
17    connected_from_addr: ConnectAddr,
18    pub last_ping: f64,
19    pub login_msg_sent: AtomicBool,
20    pub locale: Option<String>,
21
22    //TODO: Consider splitting each of these out into their own components so all the message
23    //processing systems can run in parallel with each other (though it may turn out not to
24    //matter that much).
25    general_stream: Stream,
26    ping_stream: Stream,
27    register_stream: Stream,
28    character_screen_stream: Stream,
29    in_game_stream: Stream,
30    terrain_stream: Stream,
31
32    general_stream_params: StreamParams,
33    ping_stream_params: StreamParams,
34    register_stream_params: StreamParams,
35    character_screen_stream_params: StreamParams,
36    in_game_stream_params: StreamParams,
37    terrain_stream_params: StreamParams,
38}
39
40pub struct PreparedMsg {
41    stream_id: u8,
42    message: Message,
43}
44
45impl Component for Client {
46    type Storage = specs::DenseVecStorage<Self>;
47}
48
49impl Client {
50    pub(crate) fn new(
51        client_type: ClientType,
52        participant: Participant,
53        connected_from: ConnectAddr,
54        last_ping: f64,
55        locale: Option<String>,
56        general_stream: Stream,
57        ping_stream: Stream,
58        register_stream: Stream,
59        character_screen_stream: Stream,
60        in_game_stream: Stream,
61        terrain_stream: Stream,
62    ) -> Self {
63        let general_stream_params = general_stream.params();
64        let ping_stream_params = ping_stream.params();
65        let register_stream_params = register_stream.params();
66        let character_screen_stream_params = character_screen_stream.params();
67        let in_game_stream_params = in_game_stream.params();
68        let terrain_stream_params = terrain_stream.params();
69        Client {
70            client_type,
71            participant: Some(participant),
72            current_ip_addrs: connected_from.socket_addr().into_iter().collect(),
73            connected_from_addr: connected_from,
74            last_ping,
75            locale,
76            login_msg_sent: AtomicBool::new(false),
77            general_stream,
78            ping_stream,
79            register_stream,
80            character_screen_stream,
81            in_game_stream,
82            terrain_stream,
83            general_stream_params,
84            ping_stream_params,
85            register_stream_params,
86            character_screen_stream_params,
87            in_game_stream_params,
88            terrain_stream_params,
89        }
90    }
91
92    pub(crate) fn connected_from_addr(&self) -> &ConnectAddr { &self.connected_from_addr }
93
94    pub(crate) fn send<M: Into<ServerMsg>>(&self, msg: M) -> Result<(), StreamError> {
95        // TODO: hack to avoid locking stream mutex while serializing the message,
96        // remove this when the mutexes on the Streams are removed
97        let prepared = self.prepare(msg);
98        self.send_prepared(&prepared)
99        /*match msg.into() {
100            ServerMsg::Info(m) => self.register_stream.lock().unwrap().send(m),
101            ServerMsg::Init(m) => self.register_stream.lock().unwrap().send(m),
102            ServerMsg::RegisterAnswer(m) => self.register_stream.lock().unwrap().send(m),
103            ServerMsg::General(g) => {
104                match g {
105                    //Character Screen related
106                    ServerGeneral::CharacterDataLoadResult(_)
107                    | ServerGeneral::CharacterListUpdate(_)
108                    | ServerGeneral::CharacterActionError(_)
109                    | ServerGeneral::CharacterCreated(_)
110                    | ServerGeneral::CharacterEdited(_)
111                    | ServerGeneral::CharacterSuccess => {
112                        self.character_screen_stream.lock().unwrap().send(g)
113                    },
114                    //In-game related
115                    ServerGeneral::GroupUpdate(_)
116                    | ServerGeneral::Invite { .. }
117                    | ServerGeneral::InvitePending(_)
118                    | ServerGeneral::InviteComplete { .. }
119                    | ServerGeneral::ExitInGameSuccess
120                    | ServerGeneral::InventoryUpdate(_, _)
121                    | ServerGeneral::SetViewDistance(_)
122                    | ServerGeneral::SiteEconomy(_)
123                    | ServerGeneral::Outcomes(_)
124                    | ServerGeneral::Knockback(_)
125                    | ServerGeneral::UpdatePendingTrade(_, _, _)
126                    | ServerGeneral::FinishedTrade(_)
127                    | ServerGeneral::WeatherUpdate(_) => {
128                        self.in_game_stream.lock().unwrap().send(g)
129                    },
130                    //Ingame related, terrain
131                    ServerGeneral::TerrainChunkUpdate { .. }
132                    | ServerGeneral::LodZoneUpdate { .. }
133                    | ServerGeneral::TerrainBlockUpdates(_) => {
134                        self.terrain_stream.lock().unwrap().send(g)
135                    },
136                    // Always possible
137                    ServerGeneral::PlayerListUpdate(_)
138                    | ServerGeneral::ChatMsg(_)
139                    | ServerGeneral::ChatMode(_)
140                    | ServerGeneral::SetPlayerEntity(_)
141                    | ServerGeneral::TimeOfDay(_, _)
142                    | ServerGeneral::EntitySync(_)
143                    | ServerGeneral::CompSync(_)
144                    | ServerGeneral::CreateEntity(_)
145                    | ServerGeneral::DeleteEntity(_)
146                    | ServerGeneral::Disconnect(_)
147                    | ServerGeneral::Notification(_) => self.general_stream.lock().unwrap().send(g),
148                }
149            },
150            ServerMsg::Ping(m) => self.ping_stream.lock().unwrap().send(m),
151        }*/
152    }
153
154    /// Like `send` but any errors are explicitly ignored.
155    pub(crate) fn send_fallible<M: Into<ServerMsg>>(&self, msg: M) { let _ = self.send(msg); }
156
157    pub(crate) fn send_prepared(&self, msg: &PreparedMsg) -> Result<(), StreamError> {
158        match msg.stream_id {
159            0 => self.register_stream.send_raw(&msg.message),
160            1 => self.character_screen_stream.send_raw(&msg.message),
161            2 => self.in_game_stream.send_raw(&msg.message),
162            3 => self.general_stream.send_raw(&msg.message),
163            4 => self.ping_stream.send_raw(&msg.message),
164            5 => self.terrain_stream.send_raw(&msg.message),
165            _ => unreachable!("invalid stream id"),
166        }
167    }
168
169    pub(crate) fn prepare<M: Into<ServerMsg>>(&self, msg: M) -> PreparedMsg {
170        match msg.into() {
171            ServerMsg::Info(m) => PreparedMsg::new(0, &m, &self.register_stream_params),
172            ServerMsg::Init(m) => PreparedMsg::new(0, &m, &self.register_stream_params),
173            ServerMsg::RegisterAnswer(m) => PreparedMsg::new(0, &m, &self.register_stream_params),
174            ServerMsg::General(g) => {
175                match g {
176                    // Character Screen related
177                    ServerGeneral::CharacterDataLoadResult(_)
178                    | ServerGeneral::CharacterListUpdate(_)
179                    | ServerGeneral::CharacterActionError(_)
180                    | ServerGeneral::CharacterCreated(_)
181                    | ServerGeneral::CharacterEdited(_)
182                    | ServerGeneral::CharacterSuccess
183                    | ServerGeneral::SpectatorSuccess(_) => {
184                        PreparedMsg::new(1, &g, &self.character_screen_stream_params)
185                    },
186                    // In-game related
187                    ServerGeneral::GroupUpdate(_)
188                    | ServerGeneral::Invite { .. }
189                    | ServerGeneral::InvitePending(_)
190                    | ServerGeneral::InviteComplete { .. }
191                    | ServerGeneral::ExitInGameSuccess
192                    | ServerGeneral::InventoryUpdate(_, _)
193                    | ServerGeneral::GroupInventoryUpdate(_, _)
194                    | ServerGeneral::Dialogue(_, _)
195                    | ServerGeneral::SetViewDistance(_)
196                    | ServerGeneral::Outcomes(_)
197                    | ServerGeneral::Knockback(_)
198                    | ServerGeneral::SiteEconomy(_)
199                    | ServerGeneral::UpdatePendingTrade(_, _, _)
200                    | ServerGeneral::FinishedTrade(_)
201                    | ServerGeneral::MapMarker(_)
202                    | ServerGeneral::WeatherUpdate(_)
203                    | ServerGeneral::LocalWindUpdate(_)
204                    | ServerGeneral::SpectatePosition(_)
205                    | ServerGeneral::UpdateRecipes => {
206                        PreparedMsg::new(2, &g, &self.in_game_stream_params)
207                    },
208                    // Terrain
209                    ServerGeneral::TerrainChunkUpdate { .. }
210                    | ServerGeneral::LodZoneUpdate { .. }
211                    | ServerGeneral::TerrainBlockUpdates(_) => {
212                        PreparedMsg::new(5, &g, &self.terrain_stream_params)
213                    },
214                    // Always possible
215                    ServerGeneral::PlayerListUpdate(_)
216                    | ServerGeneral::ChatMsg(_)
217                    | ServerGeneral::ChatMode(_)
218                    | ServerGeneral::SetPlayerEntity(_)
219                    | ServerGeneral::TimeOfDay(_, _, _, _)
220                    | ServerGeneral::EntitySync(_)
221                    | ServerGeneral::CompSync(_, _)
222                    | ServerGeneral::CreateEntity(_)
223                    | ServerGeneral::DeleteEntity(_)
224                    | ServerGeneral::Disconnect(_)
225                    | ServerGeneral::Notification(_)
226                    | ServerGeneral::SetPlayerRole(_)
227                    | ServerGeneral::PluginData(_) => {
228                        PreparedMsg::new(3, &g, &self.general_stream_params)
229                    },
230                }
231            },
232            ServerMsg::Ping(m) => PreparedMsg::new(4, &m, &self.ping_stream_params),
233        }
234    }
235
236    pub(crate) fn terrain_params(&self) -> StreamParams { self.terrain_stream_params.clone() }
237
238    /// Only used for Serialize Chunks in a SlowJob.
239    /// TODO: find a more elegant version for this invariant
240    pub(crate) fn prepare_chunk_update_msg(
241        terrain_chunk_update: ServerGeneral,
242        params: &StreamParams,
243    ) -> PreparedMsg {
244        if !matches!(
245            terrain_chunk_update,
246            ServerGeneral::TerrainChunkUpdate { .. }
247        ) {
248            unreachable!("You must not call this function without a terrain chunk update!")
249        }
250        PreparedMsg::new(5, &terrain_chunk_update, params)
251    }
252
253    pub(crate) fn recv<M: DeserializeOwned>(
254        &mut self,
255        stream_id: u8,
256    ) -> Result<Option<M>, StreamError> {
257        // TODO: are two systems using the same stream?? why is there contention here?
258        match stream_id {
259            0 => self.register_stream.try_recv(),
260            1 => self.character_screen_stream.try_recv(),
261            2 => self.in_game_stream.try_recv(),
262            3 => self.general_stream.try_recv(),
263            4 => self.ping_stream.try_recv(),
264            5 => self.terrain_stream.try_recv(),
265            _ => unreachable!("invalid stream id"),
266        }
267    }
268}
269
270impl PreparedMsg {
271    fn new<M: Serialize + ?Sized>(id: u8, msg: &M, stream_params: &StreamParams) -> PreparedMsg {
272        Self {
273            stream_id: id,
274            message: Message::serialize(&msg, stream_params.clone()),
275        }
276    }
277}