composition/server/net/
mod.rs1pub mod packets;
3
4use super::messages::*;
5use crate::{mctypes::*, CONFIG, FAVICON};
6use log::*;
7use packets::*;
8use serde_json::json;
9use std::sync::mpsc::Sender;
10use std::time::{Duration, Instant};
11use tokio::net::TcpStream;
12
13#[derive(PartialEq, Debug)]
16pub enum NetworkClientState {
17 Handshake,
18 Status,
19 Login,
20 Play,
21 Disconnected,
22}
23
24#[derive(Debug)]
27pub struct NetworkClient {
28 pub id: u128,
29 pub connected: bool,
30 pub stream: TcpStream,
31 pub state: NetworkClientState,
32 pub uuid: Option<String>,
33 pub username: Option<String>,
34 pub last_keep_alive: Instant,
35 pub message_sender: Sender<ServerboundMessage>,
36}
37impl NetworkClient {
38 pub fn new(
40 stream: TcpStream,
41 id: u128,
42 message_sender: Sender<ServerboundMessage>,
43 ) -> NetworkClient {
44 NetworkClient {
45 id,
46 connected: true,
47 stream,
48 state: NetworkClientState::Handshake,
49 uuid: None,
50 username: None,
51 last_keep_alive: Instant::now(),
52 message_sender,
53 }
54 }
55
56 pub async fn update(&mut self, num_players: usize) -> tokio::io::Result<()> {
61 match self.state {
63 NetworkClientState::Handshake => {
64 let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
65 let handshake = self.get_packet::<Handshake>().await?;
66 let compatible_versions = handshake.protocol_version == 47;
68 let next_state = match handshake.next_state.into() {
69 1 => NetworkClientState::Status,
70 2 => NetworkClientState::Login,
71 _ => NetworkClientState::Disconnected,
72 };
73 self.state = next_state;
74 if !compatible_versions {
76 let mut logindisconnect = LoginDisconnect::new();
77 logindisconnect.reason = MCChat {
78 text: MCString::from("Incompatible client! Server is on 1.8.9"),
79 };
80 self.send_packet(logindisconnect).await?;
81 self.state = NetworkClientState::Disconnected;
82 }
83 }
84 NetworkClientState::Status => {
85 let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
86 let _statusrequest = self.get_packet::<StatusRequest>().await?;
87 let mut statusresponse = StatusResponse::new();
88 statusresponse.json_response = json!({
89 "version": {
90 "name": "1.8.9",
91 "protocol": 47,
92 },
93 "players": {
94 "max": CONFIG.max_players,
95 "online": num_players,
96 "sample": [
97 {
98 "name": "shvr",
99 "id": "e3f58380-60bb-4714-91f2-151d525e64aa"
100 }
101 ]
102 },
103 "description": {
104 "text": CONFIG.motd
105 },
106 "favicon": format!("data:image/png;base64,{}", if FAVICON.is_ok() { radix64::STD.encode(FAVICON.as_ref().unwrap().as_slice()) } else { "".to_owned() })
107 })
108 .to_string()
109 .into();
110 self.send_packet(statusresponse).await?;
111 let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
112 let statusping = self.get_packet::<StatusPing>().await?;
113 let mut statuspong = StatusPong::new();
114 statuspong.payload = statusping.payload;
115 self.send_packet(statuspong).await?;
116 self.state = NetworkClientState::Disconnected;
117 }
118 NetworkClientState::Login => {
119 let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
120 let loginstart = self.get_packet::<LoginStart>().await?;
121 let mut loginsuccess = LoginSuccess::new();
124 loginsuccess.uuid = "00000000-0000-3000-0000-000000000000".into();
127 loginsuccess.username = loginstart.player_name;
128 self.uuid = Some(loginsuccess.uuid.clone().into());
129 self.username = Some(loginsuccess.username.clone().into());
130 self.send_packet(loginsuccess).await?;
131 self.state = NetworkClientState::Play;
132 let joingame = JoinGame::new();
133 self.send_packet(joingame).await?;
135 let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
136 let _clientsettings = self.get_packet::<ClientSettings>().await?;
137 let helditemchange = HeldItemChange::new();
139 self.send_packet(helditemchange).await?;
141 let playerpositionandlook = ClientboundPlayerPositionAndLook::new();
148 self.send_packet(playerpositionandlook).await?;
150 let spawnposition = SpawnPosition::new();
158 self.send_packet(spawnposition).await?;
159 self.keep_alive().await?;
161 self.message_sender
167 .send(ServerboundMessage::PlayerJoin(
168 self.uuid
169 .as_ref()
170 .unwrap_or(&"00000000-0000-3000-0000-000000000000".to_owned())
171 .to_string(),
172 self.username
173 .as_ref()
174 .unwrap_or(&"unknown".to_owned())
175 .to_string(),
176 ))
177 .expect("Message receiver disconnected");
178 }
179 NetworkClientState::Play => {
180 if self.last_keep_alive.elapsed() > Duration::from_millis(1000) {
181 self.keep_alive().await?;
182 }
183 let (packet_length, packet_id) = read_packet_header(&mut self.stream).await?;
184 if packet_id == Player::id() {
186 let _player = self.get_packet::<Player>().await?;
187 } else if packet_id == PlayerPosition::id() {
188 let _playerposition = self.get_packet::<PlayerPosition>().await?;
189 } else if packet_id == PlayerLook::id() {
190 let _playerlook = self.get_packet::<PlayerLook>().await?;
191 } else if packet_id == ServerboundPlayerPositionAndLook::id() {
192 let _playerpositionandlook = self
193 .get_packet::<ServerboundPlayerPositionAndLook>()
194 .await?;
195 } else if packet_id == ServerboundChatMessage::id() {
196 let serverboundchatmessage =
197 self.get_packet::<ServerboundChatMessage>().await?;
198 let reply = format!("<{}> {}", self.get_name(), serverboundchatmessage.text);
199 info!("{}", reply);
200 self.message_sender
201 .send(ServerboundMessage::Chat(reply))
202 .expect("Message receiver disconnected");
203 } else {
204 let _ = read_bytes(&mut self.stream, Into::<i32>::into(packet_length) as usize)
205 .await?;
206 }
207 }
208 NetworkClientState::Disconnected => {
209 if self.connected {
210 self.disconnect("Disconnected").await?;
211 }
212 }
213 }
214 Ok(())
215 }
216
217 pub async fn send_packet<P: PacketCommon>(&mut self, packet: P) -> tokio::io::Result<()> {
219 debug!("Sent {:?} {:#04X?} {:?}", self.state, P::id(), packet);
220 packet.write(&mut self.stream).await
221 }
222
223 pub async fn get_packet<T: PacketCommon>(&mut self) -> tokio::io::Result<T> {
225 let packet = T::read(&mut self.stream).await?;
226 debug!("Got {:?} {:#04X?} {:?}", self.state, T::id(), packet);
227 Ok(packet)
228 }
229
230 pub async fn send_chat_message<C: Into<MCChat>>(
232 &mut self,
233 message: C,
234 ) -> tokio::io::Result<()> {
235 let mut chatmessage = ClientboundChatMessage::new();
236 chatmessage.text = message.into();
237 self.send_packet(chatmessage).await?;
238 Ok(())
239 }
240
241 pub async fn disconnect<S: Into<MCString>>(&mut self, reason: S) -> tokio::io::Result<()> {
245 let mut disconnect = Disconnect::new();
246 disconnect.reason.text = reason.into();
247 self.send_packet(disconnect).await?;
248 self.force_disconnect();
249 Ok(())
250 }
251
252 pub fn force_disconnect(&mut self) {
254 self.connected = false;
255 self.state = NetworkClientState::Disconnected;
256 }
257
258 pub async fn keep_alive(&mut self) -> tokio::io::Result<()> {
260 if cfg!(debug_assertions) {
261 self.send_chat_message("keep alive").await?;
262 }
263 let clientboundkeepalive = KeepAlivePing::new();
265 self.send_packet(clientboundkeepalive).await?;
266 let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
268 let _serverboundkeepalive = self.get_packet::<KeepAlivePong>().await?;
269 self.last_keep_alive = Instant::now();
270 Ok(())
271 }
272
273 pub fn get_name(&self) -> String {
275 self.username
276 .as_ref()
277 .unwrap_or(&"unknown".to_owned())
278 .to_string()
279 }
280
281 pub async fn handle_broadcast_message(
283 &mut self,
284 message: BroadcastMessage,
285 ) -> tokio::io::Result<()> {
286 use BroadcastMessage::*;
287 match message {
288 Chat(s) => self.send_chat_message(s).await?,
289 Disconnect(reason) => self.disconnect(reason).await?,
290 }
291 Ok(())
292 }
293}