luanti_protocol/commands/server_to_client/
access_denied.rs

1use crate::wire::{
2    deser::{Deserialize, DeserializeResult, Deserializer},
3    ser::{Serialize, SerializeResult, Serializer},
4};
5use luanti_protocol_derive::{LuantiDeserialize, LuantiSerialize};
6
7#[derive(Debug, Clone, PartialEq, LuantiSerialize, LuantiDeserialize)]
8pub struct AccessDeniedCommand {
9    pub code: AccessDeniedCode,
10    pub reason: String,
11    pub reconnect: bool,
12}
13
14#[derive(Debug, Clone, PartialEq)]
15pub enum AccessDeniedCode {
16    WrongPassword,
17    UnexpectedData,
18    Singleplayer,
19    WrongVersion,
20    WrongCharsInName,
21    WrongName,
22    TooManyUsers,
23    EmptyPassword,
24    AlreadyConnected,
25    ServerFail,
26    CustomString(String),
27    Shutdown(String, bool), // custom message (or blank), should_reconnect
28    Crash(String, bool),    // custom message (or blank), should_reconnect
29}
30
31impl Serialize for AccessDeniedCode {
32    type Input = Self;
33    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
34        #![allow(clippy::enum_glob_use, reason = "improves readability")]
35        use AccessDeniedCode::*;
36        match value {
37            WrongPassword => u8::serialize(&0, ser),
38            UnexpectedData => u8::serialize(&1, ser),
39            Singleplayer => u8::serialize(&2, ser),
40            WrongVersion => u8::serialize(&3, ser),
41            WrongCharsInName => u8::serialize(&4, ser),
42            WrongName => u8::serialize(&5, ser),
43            TooManyUsers => u8::serialize(&6, ser),
44            EmptyPassword => u8::serialize(&7, ser),
45            AlreadyConnected => u8::serialize(&8, ser),
46            ServerFail => u8::serialize(&9, ser),
47            CustomString(msg) => {
48                u8::serialize(&10, ser)?;
49                String::serialize(msg, ser)?;
50                Ok(())
51            }
52            Shutdown(msg, reconnect) => {
53                u8::serialize(&11, ser)?;
54                String::serialize(msg, ser)?;
55                bool::serialize(reconnect, ser)?;
56                Ok(())
57            }
58            Crash(msg, reconnect) => {
59                u8::serialize(&12, ser)?;
60                String::serialize(msg, ser)?;
61                bool::serialize(reconnect, ser)?;
62                Ok(())
63            }
64        }
65    }
66}
67
68impl Deserialize for AccessDeniedCode {
69    type Output = Self;
70    fn deserialize(deser: &mut Deserializer<'_>) -> DeserializeResult<Self> {
71        #![allow(clippy::enum_glob_use, reason = "improves readability")]
72        use AccessDeniedCode::*;
73        let deny_code = u8::deserialize(deser)?;
74        match deny_code {
75            0 => Ok(WrongPassword),
76            1 => Ok(UnexpectedData),
77            2 => Ok(Singleplayer),
78            3 => Ok(WrongVersion),
79            4 => Ok(WrongCharsInName),
80            5 => Ok(WrongName),
81            6 => Ok(TooManyUsers),
82            7 => Ok(EmptyPassword),
83            8 => Ok(AlreadyConnected),
84            9 => Ok(ServerFail),
85            10 => Ok(CustomString(String::deserialize(deser)?)),
86            11 => Ok(Shutdown(
87                String::deserialize(deser)?,
88                (u8::deserialize(deser)? & 1) != 0,
89            )),
90            12 => Ok(Crash(
91                String::deserialize(deser)?,
92                (u8::deserialize(deser)? & 1) != 0,
93            )),
94            _ => Ok(CustomString(String::deserialize(deser)?)),
95        }
96    }
97}
98
99impl AccessDeniedCode {
100    #[must_use]
101    pub fn to_str(&self) -> &str {
102        #![allow(clippy::enum_glob_use, reason = "improves readability")]
103        use AccessDeniedCode::*;
104        match self {
105            WrongPassword => "Invalid password",
106            UnexpectedData => {
107                "Your client sent something the server didn't expect.  Try reconnecting or updating your client."
108            }
109            Singleplayer => {
110                "The server is running in simple singleplayer mode.  You cannot connect."
111            }
112            WrongVersion => {
113                "Your client's version is not supported.\nPlease contact the server administrator."
114            }
115            WrongCharsInName => "Player name contains disallowed characters",
116            WrongName => "Player name not allowed",
117            TooManyUsers => "Too many users",
118            EmptyPassword => "Empty passwords are disallowed.  Set a password and try again.",
119            AlreadyConnected => {
120                "Another client is connected with this name.  If your client closed unexpectedly, try again in a minute."
121            }
122            ServerFail => "Internal server error",
123            CustomString(msg) => {
124                if msg.is_empty() {
125                    "unknown"
126                } else {
127                    msg
128                }
129            }
130            Shutdown(msg, _) => {
131                if msg.is_empty() {
132                    "Server shutting down"
133                } else {
134                    msg
135                }
136            }
137            Crash(msg, _) => {
138                if msg.is_empty() {
139                    "The server has experienced an internal error.  You will now be disconnected."
140                } else {
141                    msg
142                }
143            }
144        }
145    }
146}