veloren_common_net/msg/
client.rs

1use super::{PingMsg, world_msg::SiteId};
2use common::{
3    ViewDistances,
4    character::CharacterId,
5    comp::{self, AdminRole, Skill},
6    event::PluginHash,
7    resources::BattleMode,
8    terrain::block::Block,
9};
10use serde::{Deserialize, Serialize};
11use vek::*;
12
13///This struct contains all messages the client might send (on different
14/// streams though). It's used to verify the correctness of the state in
15/// debug_assertions
16#[derive(Debug, Clone)]
17pub enum ClientMsg {
18    ///Send on the first connection ONCE to identify client intention for
19    /// server
20    Type(ClientType),
21    ///Send ONCE to register/auth to the server
22    Register(ClientRegister),
23    ///Msg that can be send ALWAYS as soon as we are registered, e.g. `Chat`
24    General(ClientGeneral),
25    Ping(PingMsg),
26}
27
28/*
292nd Level Enums
30*/
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
33pub enum ClientType {
34    /// Regular Client like Voxygen who plays the game
35    Game,
36    /// A Chat-only client, which doesn't want to connect via its character
37    ChatOnly,
38    /// A client that is only allowed to use spectator, does not emit
39    /// login/logout and player list events, and cannot use chat.
40    ///
41    /// Can only be used by moderators.
42    SilentSpectator,
43    /// A unprivileged bot, e.g. to request world information
44    /// Or a privileged bot, e.g. to run admin commands used by server-cli
45    Bot { privileged: bool },
46}
47
48impl ClientType {
49    pub fn is_valid_for_role(&self, role: Option<AdminRole>) -> bool {
50        match self {
51            Self::SilentSpectator => role.is_some(),
52            Self::Bot { privileged } => !privileged || role.is_some(),
53            _ => true,
54        }
55    }
56
57    pub fn emit_login_events(&self) -> bool { !matches!(self, Self::SilentSpectator) }
58
59    pub fn can_spectate(&self) -> bool { matches!(self, Self::Game | Self::SilentSpectator) }
60
61    pub fn can_enter_character(&self) -> bool { *self == Self::Game }
62
63    pub fn can_send_message(&self) -> bool { !matches!(self, Self::SilentSpectator) }
64}
65
66#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
67pub struct ClientRegister {
68    pub token_or_username: String,
69    pub locale: Option<String>,
70}
71
72/// Messages sent from the client to the server
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub enum ClientGeneral {
75    //Only in Character Screen
76    RequestCharacterList,
77    CreateCharacter {
78        alias: String,
79        mainhand: Option<String>,
80        offhand: Option<String>,
81        body: comp::Body,
82        // Character will be deleted upon death if true
83        hardcore: bool,
84        start_site: Option<SiteId>,
85    },
86    DeleteCharacter(CharacterId),
87    EditCharacter {
88        id: CharacterId,
89        alias: String,
90        body: comp::Body,
91    },
92    Character(CharacterId, ViewDistances),
93    Spectate(ViewDistances),
94    //Only in game
95    ControllerInputs(Box<comp::ControllerInputs>),
96    ControlEvent(comp::ControlEvent),
97    ControlAction(comp::ControlAction),
98    SetViewDistance(ViewDistances),
99    BreakBlock(Vec3<i32>),
100    PlaceBlock(Vec3<i32>, Block),
101    ExitInGame,
102    PlayerPhysics {
103        pos: comp::Pos,
104        vel: comp::Vel,
105        ori: comp::Ori,
106        force_counter: u64,
107    },
108    UnlockSkill(Skill),
109    RequestSiteInfo(SiteId),
110    UpdateMapMarker(comp::MapMarkerChange),
111    SetBattleMode(BattleMode),
112
113    SpectatePosition(Vec3<f32>),
114    SpectateEntity(Option<common::uid::Uid>),
115
116    //Only in Game, via terrain stream
117    TerrainChunkRequest {
118        key: Vec2<i32>,
119    },
120    LodZoneRequest {
121        key: Vec2<i32>,
122    },
123    //Always possible
124    ChatMsg(comp::Content),
125    Command(String, Vec<String>),
126    Terminate,
127    RequestPlayerPhysics {
128        server_authoritative: bool,
129    },
130    RequestLossyTerrainCompression {
131        lossy_terrain_compression: bool,
132    },
133    RequestPlugins(Vec<PluginHash>),
134}
135
136impl ClientMsg {
137    pub fn verify(
138        &self,
139        c_type: ClientType,
140        registered: bool,
141        presence: Option<comp::PresenceKind>,
142    ) -> bool {
143        match self {
144            ClientMsg::Type(t) => c_type == *t,
145            ClientMsg::Register(_) => !registered && presence.is_none(),
146            ClientMsg::General(g) => {
147                registered
148                    && match g {
149                        ClientGeneral::RequestCharacterList
150                        | ClientGeneral::CreateCharacter { .. }
151                        | ClientGeneral::EditCharacter { .. }
152                        | ClientGeneral::DeleteCharacter(_) => {
153                            c_type != ClientType::ChatOnly && presence.is_none()
154                        },
155                        ClientGeneral::Character(_, _) => {
156                            c_type == ClientType::Game && presence.is_none()
157                        },
158                        ClientGeneral::Spectate(_) => {
159                            c_type.can_spectate() && presence.is_none()
160                        },
161                        //Only in game
162                        ClientGeneral::ControllerInputs(_)
163                        | ClientGeneral::ControlEvent(_)
164                        | ClientGeneral::ControlAction(_)
165                        | ClientGeneral::SetViewDistance(_)
166                        | ClientGeneral::BreakBlock(_)
167                        | ClientGeneral::PlaceBlock(_, _)
168                        | ClientGeneral::ExitInGame
169                        | ClientGeneral::PlayerPhysics { .. }
170                        | ClientGeneral::TerrainChunkRequest { .. }
171                        | ClientGeneral::UnlockSkill(_)
172                        | ClientGeneral::RequestSiteInfo(_)
173                        | ClientGeneral::RequestPlayerPhysics { .. }
174                        | ClientGeneral::RequestLossyTerrainCompression { .. }
175                        | ClientGeneral::UpdateMapMarker(_)
176                        | ClientGeneral::SetBattleMode(_) => {
177                            c_type == ClientType::Game && presence.is_some()
178                        },
179                        ClientGeneral::SpectatePosition(_) | ClientGeneral::SpectateEntity(_) => {
180                            c_type.can_spectate() && presence.is_some()
181                        },
182                        ClientGeneral::ChatMsg(_) => {
183                            c_type.can_send_message()
184                        },
185                        //Always possible
186                        ClientGeneral::Command(_, _)
187                        | ClientGeneral::Terminate
188                        // LodZoneRequest is required by the char select screen
189                        | ClientGeneral::LodZoneRequest { .. } => true,
190                        | ClientGeneral::RequestPlugins(_) => true,
191                    }
192            },
193            ClientMsg::Ping(_) => true,
194        }
195    }
196}
197
198/*
199end of 2nd level Enums
200*/
201
202impl From<ClientType> for ClientMsg {
203    fn from(other: ClientType) -> ClientMsg { ClientMsg::Type(other) }
204}
205
206impl From<ClientRegister> for ClientMsg {
207    fn from(other: ClientRegister) -> ClientMsg { ClientMsg::Register(other) }
208}
209
210impl From<ClientGeneral> for ClientMsg {
211    fn from(other: ClientGeneral) -> ClientMsg { ClientMsg::General(other) }
212}
213
214impl From<PingMsg> for ClientMsg {
215    fn from(other: PingMsg) -> ClientMsg { ClientMsg::Ping(other) }
216}