use bytes::Bytes;
use serde::{Deserialize, Serialize};
use super::error_codes::ErrorCode;
use super::room_state::LobbyState;
use super::types::{
ConnectionInfo, GameDataEncoding, PeerConnectionInfo, PlayerId, PlayerInfo,
ProtocolInfoPayload, RateLimitInfo, RelayTransport, RoomId, SpectatorInfo,
SpectatorStateChangeReason,
};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", content = "data")]
pub enum ClientMessage {
Authenticate {
app_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
sdk_version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
platform: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
game_data_format: Option<GameDataEncoding>,
},
JoinRoom {
game_name: String,
room_code: Option<String>,
player_name: String,
max_players: Option<u8>,
supports_authority: Option<bool>,
#[serde(default)]
relay_transport: Option<RelayTransport>,
},
LeaveRoom,
GameData { data: serde_json::Value },
AuthorityRequest { become_authority: bool },
PlayerReady,
ProvideConnectionInfo { connection_info: ConnectionInfo },
Ping,
Reconnect {
player_id: PlayerId,
room_id: RoomId,
auth_token: String,
},
JoinAsSpectator {
game_name: String,
room_code: String,
spectator_name: String,
},
LeaveSpectator,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RoomJoinedPayload {
pub room_id: RoomId,
pub room_code: String,
pub player_id: PlayerId,
pub game_name: String,
pub max_players: u8,
pub supports_authority: bool,
pub current_players: Vec<PlayerInfo>,
pub is_authority: bool,
pub lobby_state: LobbyState,
pub ready_players: Vec<PlayerId>,
pub relay_type: String,
#[serde(default)]
pub current_spectators: Vec<SpectatorInfo>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReconnectedPayload {
pub room_id: RoomId,
pub room_code: String,
pub player_id: PlayerId,
pub game_name: String,
pub max_players: u8,
pub supports_authority: bool,
pub current_players: Vec<PlayerInfo>,
pub is_authority: bool,
pub lobby_state: LobbyState,
pub ready_players: Vec<PlayerId>,
pub relay_type: String,
#[serde(default)]
pub current_spectators: Vec<SpectatorInfo>,
pub missed_events: Vec<ServerMessage>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SpectatorJoinedPayload {
pub room_id: RoomId,
pub room_code: String,
pub spectator_id: PlayerId,
pub game_name: String,
pub current_players: Vec<PlayerInfo>,
pub current_spectators: Vec<SpectatorInfo>,
pub lobby_state: LobbyState,
#[serde(skip_serializing_if = "Option::is_none")]
pub reason: Option<SpectatorStateChangeReason>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", content = "data")]
pub enum ServerMessage {
Authenticated {
app_name: String,
#[serde(skip_serializing_if = "Option::is_none")]
organization: Option<String>,
rate_limits: RateLimitInfo,
},
ProtocolInfo(ProtocolInfoPayload),
AuthenticationError {
error: String,
error_code: ErrorCode,
},
RoomJoined(Box<RoomJoinedPayload>),
RoomJoinFailed {
reason: String,
#[serde(skip_serializing_if = "Option::is_none")]
error_code: Option<ErrorCode>,
},
RoomLeft,
PlayerJoined { player: PlayerInfo },
PlayerLeft { player_id: PlayerId },
GameData {
from_player: PlayerId,
data: serde_json::Value,
},
GameDataBinary {
from_player: PlayerId,
encoding: GameDataEncoding,
#[serde(with = "bytes_serde")]
payload: Bytes,
},
AuthorityChanged {
authority_player: Option<PlayerId>,
you_are_authority: bool,
},
AuthorityResponse {
granted: bool,
reason: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
error_code: Option<ErrorCode>,
},
LobbyStateChanged {
lobby_state: LobbyState,
ready_players: Vec<PlayerId>,
all_ready: bool,
},
GameStarting {
peer_connections: Vec<PeerConnectionInfo>,
},
Pong,
Reconnected(Box<ReconnectedPayload>),
ReconnectionFailed {
reason: String,
error_code: ErrorCode,
},
PlayerReconnected { player_id: PlayerId },
SpectatorJoined(Box<SpectatorJoinedPayload>),
SpectatorJoinFailed {
reason: String,
#[serde(skip_serializing_if = "Option::is_none")]
error_code: Option<ErrorCode>,
},
SpectatorLeft {
#[serde(skip_serializing_if = "Option::is_none")]
room_id: Option<RoomId>,
#[serde(skip_serializing_if = "Option::is_none")]
room_code: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
reason: Option<SpectatorStateChangeReason>,
#[serde(default)]
current_spectators: Vec<SpectatorInfo>,
},
NewSpectatorJoined {
spectator: SpectatorInfo,
#[serde(default)]
current_spectators: Vec<SpectatorInfo>,
#[serde(skip_serializing_if = "Option::is_none")]
reason: Option<SpectatorStateChangeReason>,
},
SpectatorDisconnected {
spectator_id: PlayerId,
#[serde(skip_serializing_if = "Option::is_none")]
reason: Option<SpectatorStateChangeReason>,
#[serde(default)]
current_spectators: Vec<SpectatorInfo>,
},
Error {
message: String,
#[serde(skip_serializing_if = "Option::is_none")]
error_code: Option<ErrorCode>,
},
}
mod bytes_serde {
use bytes::Bytes;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub fn serialize<S>(bytes: &Bytes, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serde_bytes::Bytes::new(bytes.as_ref()).serialize(serializer)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Bytes, D::Error>
where
D: Deserializer<'de>,
{
let vec: Vec<u8> = serde_bytes::ByteBuf::deserialize(deserializer)?.into_vec();
Ok(Bytes::from(vec))
}
}