use super::{world_msg::SiteId, PingMsg};
use common::{
character::CharacterId,
comp::{self, AdminRole, Skill},
event::PluginHash,
terrain::block::Block,
ViewDistances,
};
use serde::{Deserialize, Serialize};
use vek::*;
#[derive(Debug, Clone)]
pub enum ClientMsg {
Type(ClientType),
Register(ClientRegister),
General(ClientGeneral),
Ping(PingMsg),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ClientType {
Game,
ChatOnly,
SilentSpectator,
Bot { privileged: bool },
}
impl ClientType {
pub fn is_valid_for_role(&self, role: Option<AdminRole>) -> bool {
match self {
Self::SilentSpectator => role.is_some(),
Self::Bot { privileged } => !privileged || role.is_some(),
_ => true,
}
}
pub fn emit_login_events(&self) -> bool { !matches!(self, Self::SilentSpectator) }
pub fn can_spectate(&self) -> bool { matches!(self, Self::Game | Self::SilentSpectator) }
pub fn can_enter_character(&self) -> bool { *self == Self::Game }
pub fn can_send_message(&self) -> bool { !matches!(self, Self::SilentSpectator) }
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ClientRegister {
pub token_or_username: String,
pub locale: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ClientGeneral {
RequestCharacterList,
CreateCharacter {
alias: String,
mainhand: Option<String>,
offhand: Option<String>,
body: comp::Body,
hardcore: bool,
start_site: Option<SiteId>,
},
DeleteCharacter(CharacterId),
EditCharacter {
id: CharacterId,
alias: String,
body: comp::Body,
},
Character(CharacterId, ViewDistances),
Spectate(ViewDistances),
ControllerInputs(Box<comp::ControllerInputs>),
ControlEvent(comp::ControlEvent),
ControlAction(comp::ControlAction),
SetViewDistance(ViewDistances),
BreakBlock(Vec3<i32>),
PlaceBlock(Vec3<i32>, Block),
ExitInGame,
PlayerPhysics {
pos: comp::Pos,
vel: comp::Vel,
ori: comp::Ori,
force_counter: u64,
},
UnlockSkill(Skill),
RequestSiteInfo(SiteId),
UpdateMapMarker(comp::MapMarkerChange),
SpectatePosition(Vec3<f32>),
TerrainChunkRequest {
key: Vec2<i32>,
},
LodZoneRequest {
key: Vec2<i32>,
},
ChatMsg(String),
Command(String, Vec<String>),
Terminate,
RequestPlayerPhysics {
server_authoritative: bool,
},
RequestLossyTerrainCompression {
lossy_terrain_compression: bool,
},
RequestPlugins(Vec<PluginHash>),
}
impl ClientMsg {
pub fn verify(
&self,
c_type: ClientType,
registered: bool,
presence: Option<comp::PresenceKind>,
) -> bool {
match self {
ClientMsg::Type(t) => c_type == *t,
ClientMsg::Register(_) => !registered && presence.is_none(),
ClientMsg::General(g) => {
registered
&& match g {
ClientGeneral::RequestCharacterList
| ClientGeneral::CreateCharacter { .. }
| ClientGeneral::EditCharacter { .. }
| ClientGeneral::DeleteCharacter(_) => {
c_type != ClientType::ChatOnly && presence.is_none()
},
ClientGeneral::Character(_, _) => {
c_type == ClientType::Game && presence.is_none()
},
ClientGeneral::Spectate(_) => {
c_type.can_spectate() && presence.is_none()
},
ClientGeneral::ControllerInputs(_)
| ClientGeneral::ControlEvent(_)
| ClientGeneral::ControlAction(_)
| ClientGeneral::SetViewDistance(_)
| ClientGeneral::BreakBlock(_)
| ClientGeneral::PlaceBlock(_, _)
| ClientGeneral::ExitInGame
| ClientGeneral::PlayerPhysics { .. }
| ClientGeneral::TerrainChunkRequest { .. }
| ClientGeneral::UnlockSkill(_)
| ClientGeneral::RequestSiteInfo(_)
| ClientGeneral::RequestPlayerPhysics { .. }
| ClientGeneral::RequestLossyTerrainCompression { .. }
| ClientGeneral::UpdateMapMarker(_) => {
c_type == ClientType::Game && presence.is_some()
},
ClientGeneral::SpectatePosition(_) => {
c_type.can_spectate() && presence.is_some()
},
ClientGeneral::ChatMsg(_) => {
c_type.can_send_message()
},
ClientGeneral::Command(_, _)
| ClientGeneral::Terminate
| ClientGeneral::LodZoneRequest { .. } => true,
| ClientGeneral::RequestPlugins(_) => true,
}
},
ClientMsg::Ping(_) => true,
}
}
}
impl From<ClientType> for ClientMsg {
fn from(other: ClientType) -> ClientMsg { ClientMsg::Type(other) }
}
impl From<ClientRegister> for ClientMsg {
fn from(other: ClientRegister) -> ClientMsg { ClientMsg::Register(other) }
}
impl From<ClientGeneral> for ClientMsg {
fn from(other: ClientGeneral) -> ClientMsg { ClientMsg::General(other) }
}
impl From<PingMsg> for ClientMsg {
fn from(other: PingMsg) -> ClientMsg { ClientMsg::Ping(other) }
}