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#[derive(Debug, Clone)]
17pub enum ClientMsg {
18    Type(ClientType),
21    Register(ClientRegister),
23    General(ClientGeneral),
25    Ping(PingMsg),
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
33pub enum ClientType {
34    Game,
36    ChatOnly,
38    SilentSpectator,
43    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#[derive(Debug, Clone, Serialize, Deserialize)]
74pub enum ClientGeneral {
75    RequestCharacterList,
77    CreateCharacter {
78        alias: String,
79        mainhand: Option<String>,
80        offhand: Option<String>,
81        body: comp::Body,
82        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    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    TerrainChunkRequest {
118        key: Vec2<i32>,
119    },
120    LodZoneRequest {
121        key: Vec2<i32>,
122    },
123    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                        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                        ClientGeneral::Command(_, _)
187                        | ClientGeneral::Terminate
188                        | ClientGeneral::LodZoneRequest { .. } => true,
190                        | ClientGeneral::RequestPlugins(_) => true,
191                    }
192            },
193            ClientMsg::Ping(_) => true,
194        }
195    }
196}
197
198impl 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}