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}