1use super::{PingMsg, world_msg::SiteId};
2use common::{
3 ViewDistances,
4 character::CharacterId,
5 comp::{self, AdminRole, Skill},
6 event::PluginHash,
7 terrain::block::Block,
8};
9use serde::{Deserialize, Serialize};
10use vek::*;
11
12#[derive(Debug, Clone)]
16pub enum ClientMsg {
17 Type(ClientType),
20 Register(ClientRegister),
22 General(ClientGeneral),
24 Ping(PingMsg),
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
32pub enum ClientType {
33 Game,
35 ChatOnly,
37 SilentSpectator,
42 Bot { privileged: bool },
45}
46
47impl ClientType {
48 pub fn is_valid_for_role(&self, role: Option<AdminRole>) -> bool {
49 match self {
50 Self::SilentSpectator => role.is_some(),
51 Self::Bot { privileged } => !privileged || role.is_some(),
52 _ => true,
53 }
54 }
55
56 pub fn emit_login_events(&self) -> bool { !matches!(self, Self::SilentSpectator) }
57
58 pub fn can_spectate(&self) -> bool { matches!(self, Self::Game | Self::SilentSpectator) }
59
60 pub fn can_enter_character(&self) -> bool { *self == Self::Game }
61
62 pub fn can_send_message(&self) -> bool { !matches!(self, Self::SilentSpectator) }
63}
64
65#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
66pub struct ClientRegister {
67 pub token_or_username: String,
68 pub locale: Option<String>,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
73pub enum ClientGeneral {
74 RequestCharacterList,
76 CreateCharacter {
77 alias: String,
78 mainhand: Option<String>,
79 offhand: Option<String>,
80 body: comp::Body,
81 hardcore: bool,
83 start_site: Option<SiteId>,
84 },
85 DeleteCharacter(CharacterId),
86 EditCharacter {
87 id: CharacterId,
88 alias: String,
89 body: comp::Body,
90 },
91 Character(CharacterId, ViewDistances),
92 Spectate(ViewDistances),
93 ControllerInputs(Box<comp::ControllerInputs>),
95 ControlEvent(comp::ControlEvent),
96 ControlAction(comp::ControlAction),
97 SetViewDistance(ViewDistances),
98 BreakBlock(Vec3<i32>),
99 PlaceBlock(Vec3<i32>, Block),
100 ExitInGame,
101 PlayerPhysics {
102 pos: comp::Pos,
103 vel: comp::Vel,
104 ori: comp::Ori,
105 force_counter: u64,
106 },
107 UnlockSkill(Skill),
108 RequestSiteInfo(SiteId),
109 UpdateMapMarker(comp::MapMarkerChange),
110
111 SpectatePosition(Vec3<f32>),
112 TerrainChunkRequest {
114 key: Vec2<i32>,
115 },
116 LodZoneRequest {
117 key: Vec2<i32>,
118 },
119 ChatMsg(comp::Content),
121 Command(String, Vec<String>),
122 Terminate,
123 RequestPlayerPhysics {
124 server_authoritative: bool,
125 },
126 RequestLossyTerrainCompression {
127 lossy_terrain_compression: bool,
128 },
129 RequestPlugins(Vec<PluginHash>),
130}
131
132impl ClientMsg {
133 pub fn verify(
134 &self,
135 c_type: ClientType,
136 registered: bool,
137 presence: Option<comp::PresenceKind>,
138 ) -> bool {
139 match self {
140 ClientMsg::Type(t) => c_type == *t,
141 ClientMsg::Register(_) => !registered && presence.is_none(),
142 ClientMsg::General(g) => {
143 registered
144 && match g {
145 ClientGeneral::RequestCharacterList
146 | ClientGeneral::CreateCharacter { .. }
147 | ClientGeneral::EditCharacter { .. }
148 | ClientGeneral::DeleteCharacter(_) => {
149 c_type != ClientType::ChatOnly && presence.is_none()
150 },
151 ClientGeneral::Character(_, _) => {
152 c_type == ClientType::Game && presence.is_none()
153 },
154 ClientGeneral::Spectate(_) => {
155 c_type.can_spectate() && presence.is_none()
156 },
157 ClientGeneral::ControllerInputs(_)
159 | ClientGeneral::ControlEvent(_)
160 | ClientGeneral::ControlAction(_)
161 | ClientGeneral::SetViewDistance(_)
162 | ClientGeneral::BreakBlock(_)
163 | ClientGeneral::PlaceBlock(_, _)
164 | ClientGeneral::ExitInGame
165 | ClientGeneral::PlayerPhysics { .. }
166 | ClientGeneral::TerrainChunkRequest { .. }
167 | ClientGeneral::UnlockSkill(_)
168 | ClientGeneral::RequestSiteInfo(_)
169 | ClientGeneral::RequestPlayerPhysics { .. }
170 | ClientGeneral::RequestLossyTerrainCompression { .. }
171 | ClientGeneral::UpdateMapMarker(_) => {
172 c_type == ClientType::Game && presence.is_some()
173 },
174 ClientGeneral::SpectatePosition(_) => {
175 c_type.can_spectate() && presence.is_some()
176 },
177 ClientGeneral::ChatMsg(_) => {
178 c_type.can_send_message()
179 },
180 ClientGeneral::Command(_, _)
182 | ClientGeneral::Terminate
183 | ClientGeneral::LodZoneRequest { .. } => true,
185 | ClientGeneral::RequestPlugins(_) => true,
186 }
187 },
188 ClientMsg::Ping(_) => true,
189 }
190 }
191}
192
193impl From<ClientType> for ClientMsg {
198 fn from(other: ClientType) -> ClientMsg { ClientMsg::Type(other) }
199}
200
201impl From<ClientRegister> for ClientMsg {
202 fn from(other: ClientRegister) -> ClientMsg { ClientMsg::Register(other) }
203}
204
205impl From<ClientGeneral> for ClientMsg {
206 fn from(other: ClientGeneral) -> ClientMsg { ClientMsg::General(other) }
207}
208
209impl From<PingMsg> for ClientMsg {
210 fn from(other: PingMsg) -> ClientMsg { ClientMsg::Ping(other) }
211}