evoke_core/client_server/
mod.rs

1//! Client-Server kind of sessions.
2
3#![allow(clippy::eval_order_dependence, clippy::type_complexity)]
4
5use std::{mem::align_of, num::NonZeroU64};
6
7use alkahest::{Pack, Schema, SchemaUnpack, Seq};
8
9mod client;
10mod server;
11
12pub use self::{client::*, server::*};
13
14/// Server-wide unique id generated by server and given to the client's player.
15#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
16#[repr(transparent)]
17pub struct PlayerId(pub NonZeroU64);
18
19#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
20#[error("Zero PlayerId unpacked")]
21pub struct ZeroPlayerIdError;
22
23#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
24#[repr(transparent)]
25pub struct ClientId(pub NonZeroU64);
26
27impl SchemaUnpack<'_> for PlayerId {
28    type Unpacked = Result<Self, ZeroPlayerIdError>;
29}
30
31impl Schema for PlayerId {
32    type Packed = u64;
33
34    fn align() -> usize {
35        align_of::<u64>()
36    }
37
38    fn unpack(packed: u64, _input: &[u8]) -> Result<Self, ZeroPlayerIdError> {
39        NonZeroU64::new(packed)
40            .map(PlayerId)
41            .ok_or(ZeroPlayerIdError)
42    }
43}
44
45impl Pack<PlayerId> for PlayerId {
46    fn pack(self, _offset: usize, _output: &mut [u8]) -> (u64, usize) {
47        (self.0.get(), 0)
48    }
49}
50
51/// More efficient schema replacement for `Option<PlayerId>`
52pub struct MaybePlayerId;
53
54impl SchemaUnpack<'_> for MaybePlayerId {
55    type Unpacked = Option<PlayerId>;
56}
57
58impl Schema for MaybePlayerId {
59    type Packed = u64;
60
61    fn align() -> usize {
62        align_of::<u64>()
63    }
64
65    fn unpack(packed: u64, _input: &[u8]) -> Option<PlayerId> {
66        NonZeroU64::new(packed).map(PlayerId)
67    }
68}
69
70impl Pack<MaybePlayerId> for PlayerId {
71    fn pack(self, _offset: usize, _output: &mut [u8]) -> (u64, usize) {
72        (self.0.get(), 0)
73    }
74}
75
76impl Pack<MaybePlayerId> for Option<PlayerId> {
77    fn pack(self, _offset: usize, _output: &mut [u8]) -> (u64, usize) {
78        (self.map_or(0, |pid| pid.0.get()), 0)
79    }
80}
81
82#[allow(unused)]
83#[derive(Schema)]
84enum ClientMessage<P: Schema = (), I: Schema = ()> {
85    Connect {
86        token: alkahest::Str,
87    },
88    AddPlayer {
89        player: P,
90    },
91    Inputs {
92        step: u64,
93        next_update_step: u64,
94        inputs: Seq<(PlayerId, I)>,
95    },
96}
97
98#[allow(unused)]
99#[derive(Schema)]
100enum ServerMessage<J: Schema = (), U: Schema = ()> {
101    Connected { step: u64 },
102    PlayerJoined { info: J },
103    Updates { server_step: u64, updates: U },
104}