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 TerrainChunkRequest {
116 key: Vec2<i32>,
117 },
118 LodZoneRequest {
119 key: Vec2<i32>,
120 },
121 ChatMsg(comp::Content),
123 Command(String, Vec<String>),
124 Terminate,
125 RequestPlayerPhysics {
126 server_authoritative: bool,
127 },
128 RequestLossyTerrainCompression {
129 lossy_terrain_compression: bool,
130 },
131 RequestPlugins(Vec<PluginHash>),
132}
133
134impl ClientMsg {
135 pub fn verify(
136 &self,
137 c_type: ClientType,
138 registered: bool,
139 presence: Option<comp::PresenceKind>,
140 ) -> bool {
141 match self {
142 ClientMsg::Type(t) => c_type == *t,
143 ClientMsg::Register(_) => !registered && presence.is_none(),
144 ClientMsg::General(g) => {
145 registered
146 && match g {
147 ClientGeneral::RequestCharacterList
148 | ClientGeneral::CreateCharacter { .. }
149 | ClientGeneral::EditCharacter { .. }
150 | ClientGeneral::DeleteCharacter(_) => {
151 c_type != ClientType::ChatOnly && presence.is_none()
152 },
153 ClientGeneral::Character(_, _) => {
154 c_type == ClientType::Game && presence.is_none()
155 },
156 ClientGeneral::Spectate(_) => {
157 c_type.can_spectate() && presence.is_none()
158 },
159 ClientGeneral::ControllerInputs(_)
161 | ClientGeneral::ControlEvent(_)
162 | ClientGeneral::ControlAction(_)
163 | ClientGeneral::SetViewDistance(_)
164 | ClientGeneral::BreakBlock(_)
165 | ClientGeneral::PlaceBlock(_, _)
166 | ClientGeneral::ExitInGame
167 | ClientGeneral::PlayerPhysics { .. }
168 | ClientGeneral::TerrainChunkRequest { .. }
169 | ClientGeneral::UnlockSkill(_)
170 | ClientGeneral::RequestSiteInfo(_)
171 | ClientGeneral::RequestPlayerPhysics { .. }
172 | ClientGeneral::RequestLossyTerrainCompression { .. }
173 | ClientGeneral::UpdateMapMarker(_)
174 | ClientGeneral::SetBattleMode(_) => {
175 c_type == ClientType::Game && presence.is_some()
176 },
177 ClientGeneral::SpectatePosition(_) => {
178 c_type.can_spectate() && presence.is_some()
179 },
180 ClientGeneral::ChatMsg(_) => {
181 c_type.can_send_message()
182 },
183 ClientGeneral::Command(_, _)
185 | ClientGeneral::Terminate
186 | ClientGeneral::LodZoneRequest { .. } => true,
188 | ClientGeneral::RequestPlugins(_) => true,
189 }
190 },
191 ClientMsg::Ping(_) => true,
192 }
193 }
194}
195
196impl From<ClientType> for ClientMsg {
201 fn from(other: ClientType) -> ClientMsg { ClientMsg::Type(other) }
202}
203
204impl From<ClientRegister> for ClientMsg {
205 fn from(other: ClientRegister) -> ClientMsg { ClientMsg::Register(other) }
206}
207
208impl From<ClientGeneral> for ClientMsg {
209 fn from(other: ClientGeneral) -> ClientMsg { ClientMsg::General(other) }
210}
211
212impl From<PingMsg> for ClientMsg {
213 fn from(other: PingMsg) -> ClientMsg { ClientMsg::Ping(other) }
214}