nimble_protocol/
host_to_client.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/nimble-rust/nimble
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5
6use crate::serialize::{
7    CombinedSteps, InternalAllParticipantVectors, InternalAuthoritativeStepRange,
8};
9use crate::{ClientRequestId, SessionConnectionSecret};
10use flood_rs::{Deserialize, ReadOctetStream, Serialize, WriteOctetStream};
11use log::trace;
12use nimble_blob_stream::prelude::SenderToReceiverFrontCommands;
13use nimble_participant::ParticipantId;
14use std::fmt::{Debug, Display, Formatter};
15use std::io;
16use tick_id::TickId;
17
18#[repr(u8)]
19#[allow(clippy::module_name_repetitions)] // TODO: Rename module or enum
20pub enum HostToClientCommand {
21    GameStep = 0x08,
22    JoinGame = 0x09,
23    DownloadGameState = 0x0B,
24    BlobStreamChannel = 0x0C,
25    Connect = 0x0D,
26    Pong = 0x0E,
27}
28
29impl TryFrom<u8> for HostToClientCommand {
30    type Error = io::Error;
31
32    fn try_from(value: u8) -> io::Result<Self> {
33        Ok(match value {
34            0x09 => Self::JoinGame,
35            0x08 => Self::GameStep,
36            0x0B => Self::DownloadGameState,
37            0x0C => Self::BlobStreamChannel,
38            0x0D => Self::Connect,
39            0x0E => Self::Pong,
40            _ => Err(io::Error::new(
41                io::ErrorKind::InvalidData,
42                format!("Unknown host to client command 0x{value:0X}"),
43            ))?,
44        })
45    }
46}
47
48#[derive(Debug, Eq, PartialEq, Copy, Clone)]
49pub struct TickIdUtil;
50
51impl TickIdUtil {
52    /// # Errors
53    ///
54    /// `io::Error` // TODO:
55    pub fn to_stream(tick_id: TickId, stream: &mut impl WriteOctetStream) -> io::Result<()> {
56        stream.write_u32(tick_id.0)
57    }
58
59    /// # Errors
60    ///
61    /// `io::Error` // TODO:
62    pub fn from_stream(stream: &mut impl ReadOctetStream) -> io::Result<TickId> {
63        Ok(TickId(stream.read_u32()?))
64    }
65}
66
67#[derive(Debug, PartialEq, Eq)]
68pub struct DownloadGameStateResponse {
69    pub client_request: u8,
70    pub tick_id: TickId,
71    pub blob_stream_channel: u16,
72}
73
74impl Display for DownloadGameStateResponse {
75    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
76        write!(
77            f,
78            "download game state response {} {} {}",
79            self.client_request, self.tick_id, self.blob_stream_channel
80        )
81    }
82}
83
84impl DownloadGameStateResponse {
85    /// # Errors
86    ///
87    /// `io::Error` // TODO:
88    pub fn to_stream(&self, stream: &mut impl WriteOctetStream) -> io::Result<()> {
89        stream.write_u8(self.client_request)?;
90        TickIdUtil::to_stream(self.tick_id, stream)?;
91        stream.write_u16(self.blob_stream_channel)
92    }
93
94    /// # Errors
95    ///
96    /// `io::Error` // TODO:
97    pub fn from_stream(stream: &mut impl ReadOctetStream) -> io::Result<Self> {
98        Ok(Self {
99            client_request: stream.read_u8()?,
100            tick_id: TickIdUtil::from_stream(stream)?,
101            blob_stream_channel: stream.read_u16()?,
102        })
103    }
104}
105
106#[derive(Debug, PartialEq, Eq)]
107pub struct GameStatePart {
108    pub blob_stream_command: SenderToReceiverFrontCommands,
109}
110
111#[derive(Debug)]
112pub struct ConnectResponse {
113    pub flags: u8,
114    pub client_request_id: ClientRequestId,
115}
116
117impl ConnectResponse {
118    /// # Errors
119    ///
120    /// `io::Error` // TODO:
121    pub fn to_stream(&self, stream: &mut impl WriteOctetStream) -> io::Result<()> {
122        stream.write_u8(self.flags)?;
123        stream.write_u8(self.client_request_id.0)?;
124        Ok(())
125    }
126
127    /// # Errors
128    ///
129    /// `io::Error` // TODO:
130    pub fn from_stream(stream: &mut impl ReadOctetStream) -> io::Result<Self> {
131        Ok(Self {
132            flags: stream.read_u8()?,
133            client_request_id: ClientRequestId(stream.read_u8()?),
134        })
135    }
136}
137
138#[derive(Debug, PartialEq, Eq)]
139pub struct ConnectionAccepted {
140    pub flags: u8,
141    pub response_to_request: ClientRequestId,
142}
143
144impl Display for ConnectionAccepted {
145    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
146        write!(
147            f,
148            "connection accepted {} {}",
149            self.flags, self.response_to_request
150        )
151    }
152}
153
154impl ConnectionAccepted {
155    /// # Errors
156    ///
157    /// `io::Error` // TODO:
158    pub fn to_stream(&self, stream: &mut impl WriteOctetStream) -> io::Result<()> {
159        stream.write_u8(self.flags)?;
160        self.response_to_request.serialize(stream)?;
161        Ok(())
162    }
163
164    /// # Errors
165    ///
166    /// `io::Error` // TODO:
167    pub fn from_stream(stream: &mut impl ReadOctetStream) -> io::Result<Self> {
168        Ok(Self {
169            flags: stream.read_u8()?,
170            response_to_request: ClientRequestId::deserialize(stream)?,
171        })
172    }
173}
174
175#[derive(Debug)]
176pub struct PongInfo {
177    pub lower_millis: u16,
178}
179
180impl Serialize for PongInfo {
181    fn serialize(&self, stream: &mut impl WriteOctetStream) -> io::Result<()> {
182        stream.write_u16(self.lower_millis)
183    }
184}
185
186impl Deserialize for PongInfo {
187    fn deserialize(stream: &mut impl ReadOctetStream) -> io::Result<Self> {
188        Ok(Self {
189            lower_millis: stream.read_u16()?,
190        })
191    }
192}
193
194#[derive(Debug)]
195#[allow(clippy::module_name_repetitions)] // TODO: Rename module or enum
196pub enum HostToClientCommands<StepT: Deserialize + Serialize + Debug + Clone + Display> {
197    JoinGame(JoinGameAccepted),
198    GameStep(GameStepResponse<StepT>),
199    DownloadGameState(DownloadGameStateResponse),
200    BlobStreamChannel(SenderToReceiverFrontCommands),
201    ConnectType(ConnectionAccepted),
202    Pong(PongInfo),
203}
204
205impl<StepT: Clone + Debug + Serialize + Deserialize + Display> Serialize
206    for HostToClientCommands<StepT>
207{
208    fn serialize(&self, stream: &mut impl WriteOctetStream) -> io::Result<()> {
209        stream.write_u8(self.into())?;
210        match self {
211            Self::JoinGame(join_game_response) => join_game_response.to_stream(stream),
212            Self::GameStep(game_step_response) => game_step_response.to_stream(stream),
213            Self::DownloadGameState(download_game_state_response) => {
214                download_game_state_response.to_stream(stream)
215            }
216            Self::BlobStreamChannel(blob_stream_command) => blob_stream_command.to_stream(stream),
217            Self::ConnectType(connect_response) => connect_response.to_stream(stream),
218            Self::Pong(pong_info) => pong_info.serialize(stream),
219        }
220    }
221}
222
223impl<StepT: Clone + Debug + Serialize + Deserialize + Display> Display
224    for HostToClientCommands<StepT>
225{
226    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
227        match self {
228            Self::JoinGame(join_game_response) => {
229                write!(f, "JoinGameResponse({join_game_response})")
230            }
231            Self::GameStep(game_step_response) => {
232                write!(f, "GameStepResponse({game_step_response})")
233            }
234            Self::DownloadGameState(download_game_state_response) => {
235                write!(f, "DownloadGameState({download_game_state_response})")
236            }
237            Self::BlobStreamChannel(blob_stream_command) => {
238                write!(f, "BlobStreamChannel({blob_stream_command})")
239            }
240            Self::ConnectType(connect_response) => {
241                write!(f, "ConnectResponse({connect_response})")
242            }
243            Self::Pong(pong_info) => write!(f, "Pong({pong_info:?})"),
244        }
245    }
246}
247
248impl<StepT: Clone + Debug + Serialize + Deserialize + Display> Deserialize
249    for HostToClientCommands<StepT>
250{
251    fn deserialize(stream: &mut impl ReadOctetStream) -> io::Result<Self> {
252        let command_value = stream.read_u8()?;
253        let command = HostToClientCommand::try_from(command_value)?;
254        Ok(match command {
255            HostToClientCommand::JoinGame => Self::JoinGame(JoinGameAccepted::from_stream(stream)?),
256            HostToClientCommand::GameStep => Self::GameStep(GameStepResponse::from_stream(stream)?),
257            HostToClientCommand::DownloadGameState => {
258                Self::DownloadGameState(DownloadGameStateResponse::from_stream(stream)?)
259            }
260            HostToClientCommand::BlobStreamChannel => {
261                Self::BlobStreamChannel(SenderToReceiverFrontCommands::from_stream(stream)?)
262            }
263            HostToClientCommand::Connect => {
264                Self::ConnectType(ConnectionAccepted::from_stream(stream)?)
265            }
266            HostToClientCommand::Pong => Self::Pong(PongInfo::deserialize(stream)?),
267        })
268    }
269}
270
271impl<StepT: Deserialize + Serialize + Debug + Display + Clone> From<&HostToClientCommands<StepT>>
272    for u8
273{
274    fn from(command: &HostToClientCommands<StepT>) -> Self {
275        match command {
276            HostToClientCommands::JoinGame(_) => HostToClientCommand::JoinGame as Self,
277            HostToClientCommands::GameStep(_) => HostToClientCommand::GameStep as Self,
278            HostToClientCommands::DownloadGameState(_) => {
279                HostToClientCommand::DownloadGameState as Self
280            }
281            HostToClientCommands::BlobStreamChannel(_) => {
282                HostToClientCommand::BlobStreamChannel as Self
283            }
284            HostToClientCommands::ConnectType(_) => HostToClientCommand::Connect as Self,
285            HostToClientCommands::Pong(_) => HostToClientCommand::Pong as Self,
286        }
287    }
288}
289
290#[derive(Debug, PartialEq, Eq)]
291pub struct PartyAndSessionSecret {
292    pub session_secret: SessionConnectionSecret,
293    pub party_id: u8,
294}
295
296impl PartyAndSessionSecret {
297    /// # Errors
298    ///
299    /// `io::Error` // TODO:
300    pub fn to_stream(&self, stream: &mut impl WriteOctetStream) -> io::Result<()> {
301        self.session_secret.to_stream(stream)?;
302        stream.write_u8(self.party_id)
303    }
304
305    /// # Errors
306    ///
307    /// `io::Error` // TODO:
308    pub fn from_stream(stream: &mut impl ReadOctetStream) -> io::Result<Self> {
309        Ok(Self {
310            session_secret: SessionConnectionSecret::from_stream(stream)?,
311            party_id: stream.read_u8()?,
312        })
313    }
314}
315
316#[derive(Debug, PartialEq, Eq)]
317pub struct JoinGameParticipant {
318    pub local_index: u8,
319    pub participant_id: ParticipantId,
320}
321
322impl JoinGameParticipant {
323    /// # Errors
324    ///
325    /// `io::Error` // TODO:
326    pub fn to_stream(&self, stream: &mut impl WriteOctetStream) -> io::Result<()> {
327        stream.write_u8(self.local_index)?;
328        self.participant_id.serialize(stream)?;
329        Ok(())
330    }
331
332    /// # Errors
333    ///
334    /// `io::Error` // TODO:
335    pub fn from_stream(stream: &mut impl ReadOctetStream) -> io::Result<Self> {
336        Ok(Self {
337            local_index: stream.read_u8()?,
338            participant_id: ParticipantId::deserialize(stream)?,
339        })
340    }
341}
342
343#[derive(Debug)]
344pub struct JoinGameParticipants(pub Vec<JoinGameParticipant>);
345
346impl JoinGameParticipants {
347    /// # Errors
348    ///
349    /// `io::Error` // TODO:
350    pub fn to_stream(&self, stream: &mut impl WriteOctetStream) -> io::Result<()> {
351        stream.write_u8(self.0.len() as u8)?;
352        for join_game_participant in &self.0 {
353            join_game_participant.to_stream(stream)?;
354        }
355        Ok(())
356    }
357
358    /// # Errors
359    ///
360    /// `io::Error` // TODO:
361    pub fn from_stream(stream: &mut impl ReadOctetStream) -> io::Result<Self> {
362        let count = stream.read_u8()?;
363        let mut vec = Vec::<JoinGameParticipant>::with_capacity(count as usize);
364        for _ in 0..count {
365            vec.push(JoinGameParticipant::from_stream(stream)?);
366        }
367
368        Ok(Self(vec))
369    }
370}
371
372#[derive(Debug)]
373pub struct JoinGameAccepted {
374    pub client_request_id: ClientRequestId,
375    pub party_and_session_secret: PartyAndSessionSecret,
376    pub participants: JoinGameParticipants,
377}
378
379impl Display for JoinGameAccepted {
380    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
381        write!(
382            f,
383            "JoinGameAccepted {} {:?} {:?}",
384            self.client_request_id, self.party_and_session_secret, self.participants
385        )
386    }
387}
388
389impl JoinGameAccepted {
390    /// # Errors
391    ///
392    /// `io::Error` // TODO:
393    pub fn to_stream(&self, stream: &mut impl WriteOctetStream) -> io::Result<()> {
394        self.client_request_id.serialize(stream)?;
395        self.party_and_session_secret.to_stream(stream)?;
396        self.participants.to_stream(stream)
397    }
398
399    /// # Errors
400    ///
401    /// `io::Error` // TODO:
402    pub fn from_stream(stream: &mut impl ReadOctetStream) -> io::Result<Self> {
403        Ok(Self {
404            client_request_id: ClientRequestId::deserialize(stream)?,
405            party_and_session_secret: PartyAndSessionSecret::from_stream(stream)?,
406            participants: JoinGameParticipants::from_stream(stream)?,
407        })
408    }
409}
410
411#[derive(Debug, PartialEq, Eq)]
412pub struct GameStepResponseHeader {
413    pub connection_buffer_count: u8,
414    pub delta_buffer: i8,
415    pub next_expected_tick_id: TickId,
416}
417
418impl Display for GameStepResponseHeader {
419    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
420        write!(
421            f,
422            "game_step_response: count:{} expected:{} delta-buf:{}",
423            self.connection_buffer_count, self.next_expected_tick_id, self.delta_buffer
424        )
425    }
426}
427
428impl GameStepResponseHeader {
429    /// # Errors
430    ///
431    /// `io::Error` // TODO:
432    pub fn to_stream(&self, stream: &mut impl WriteOctetStream) -> io::Result<()> {
433        stream.write_u8(self.connection_buffer_count)?;
434        stream.write_i8(self.delta_buffer)?;
435        TickIdUtil::to_stream(self.next_expected_tick_id, stream)
436    }
437
438    /// # Errors
439    ///
440    /// `io::Error` // TODO:
441    pub fn from_stream(stream: &mut impl ReadOctetStream) -> io::Result<Self> {
442        Ok(Self {
443            connection_buffer_count: stream.read_u8()?,
444            delta_buffer: stream.read_i8()?,
445            next_expected_tick_id: TickIdUtil::from_stream(stream)?,
446        })
447    }
448}
449
450impl<StepT: Deserialize + Serialize + Debug + Clone + Display>
451    InternalAuthoritativeStepRange<StepT>
452{
453    /// # Errors
454    ///
455    /// `io::Error` // TODO:
456    pub fn to_stream(&self, stream: &mut impl WriteOctetStream) -> io::Result<()> {
457        stream.write_u8(self.delta_tick_id_from_previous)?;
458
459        self.authoritative_steps.serialize(stream)?;
460
461        Ok(())
462    }
463
464    /// # Errors
465    ///
466    /// `io::Error` // TODO:
467    pub fn from_stream(stream: &mut impl ReadOctetStream) -> io::Result<Self> {
468        let delta_steps = stream.read_u8()?;
469
470        let authoritative_combined_step = InternalAllParticipantVectors::deserialize(stream)?;
471
472        Ok(Self {
473            delta_tick_id_from_previous: delta_steps,
474            authoritative_steps: authoritative_combined_step,
475        })
476    }
477}
478
479#[derive(Debug)]
480pub struct AuthoritativeStepRanges<StepT: Deserialize + Serialize + Debug + Clone + Display> {
481    pub ranges: Vec<CombinedSteps<StepT>>,
482}
483
484impl<StepT: Deserialize + Serialize + Debug + Clone + Display> Display
485    for AuthoritativeStepRanges<StepT>
486{
487    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
488        write!(f, "auth_steps range-count:{} ranges:", self.ranges.len())?;
489
490        for range in &self.ranges {
491            write!(f, "\n{range}")?;
492        }
493
494        Ok(())
495    }
496}
497
498impl<StepT: Deserialize + Serialize + Debug + Clone + Display> Serialize
499    for AuthoritativeStepRanges<StepT>
500{
501    fn serialize(&self, stream: &mut impl WriteOctetStream) -> io::Result<()>
502    where
503        Self: Sized,
504    {
505        let mut converted_ranges = Vec::new();
506
507        let root_tick_id = if self.ranges.is_empty() {
508            TickId(0)
509        } else {
510            self.ranges[0].tick_id
511        };
512        let mut tick_id = root_tick_id;
513        for auth_range in &self.ranges {
514            let delta_ticks_from_previous = u8::try_from(auth_range.tick_id - tick_id)
515                .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "ranges are incorrect"))?;
516            tick_id = auth_range.tick_id + auth_range.steps.len() as u32;
517
518            let internal = auth_range.to_internal();
519
520            let range = InternalAuthoritativeStepRange {
521                delta_tick_id_from_previous: delta_ticks_from_previous,
522                authoritative_steps: internal,
523            };
524            converted_ranges.push(range);
525        }
526
527        let all_ranges = InternalAuthoritativeStepRanges {
528            root_tick_id,
529            ranges: converted_ranges,
530        };
531
532        all_ranges.to_stream(stream)
533    }
534}
535
536impl<StepT: Deserialize + Serialize + Debug + Clone + Display> Deserialize
537    for AuthoritativeStepRanges<StepT>
538{
539    fn deserialize(stream: &mut impl ReadOctetStream) -> io::Result<Self>
540    where
541        Self: Sized,
542    {
543        let internal_auth_step_ranges =
544            InternalAuthoritativeStepRanges::<StepT>::from_stream(stream)?;
545        let mut tick_id = internal_auth_step_ranges.root_tick_id;
546
547        let mut converted_ranges = Vec::new();
548        for internal_step_range in &internal_auth_step_ranges.ranges {
549            tick_id += internal_step_range.delta_tick_id_from_previous as u32;
550
551            let combined_steps =
552                CombinedSteps::from_internal(&internal_step_range.authoritative_steps, tick_id);
553
554            converted_ranges.push(combined_steps);
555        }
556
557        Ok(Self {
558            ranges: converted_ranges,
559        })
560    }
561}
562
563#[derive(Debug)]
564pub struct InternalAuthoritativeStepRanges<StepT: Deserialize + Serialize + Debug + Clone + Display>
565{
566    pub root_tick_id: TickId,
567    pub ranges: Vec<InternalAuthoritativeStepRange<StepT>>,
568}
569
570impl<StepT: Deserialize + Serialize + Debug + Clone + Display>
571    InternalAuthoritativeStepRanges<StepT>
572{
573    /// # Errors
574    ///
575    /// `io::Error` // TODO:
576    pub fn to_stream(&self, stream: &mut impl WriteOctetStream) -> io::Result<()> {
577        TickIdUtil::to_stream(self.root_tick_id, stream)?;
578        stream.write_u8(self.ranges.len() as u8)?;
579        trace!(
580            "tick_id: {} range_count: {}",
581            self.root_tick_id,
582            self.ranges.len()
583        );
584        for range in &self.ranges {
585            range.to_stream(stream)?;
586        }
587        Ok(())
588    }
589
590    /// # Errors
591    ///
592    /// `io::Error` // TODO:
593    pub fn from_stream(stream: &mut impl ReadOctetStream) -> io::Result<Self> {
594        let root_tick_id = TickIdUtil::from_stream(stream)?;
595        let range_count = stream.read_u8()?;
596
597        let mut authoritative_step_ranges =
598            Vec::<InternalAuthoritativeStepRange<StepT>>::with_capacity(range_count as usize);
599
600        for _ in 0..range_count {
601            authoritative_step_ranges.push(InternalAuthoritativeStepRange::from_stream(stream)?);
602        }
603
604        Ok(Self {
605            root_tick_id,
606            ranges: authoritative_step_ranges,
607        })
608    }
609}
610
611#[derive(Debug)]
612pub struct GameStepResponse<StepT: Serialize + Deserialize + Debug + Clone + Display> {
613    pub response_header: GameStepResponseHeader,
614    pub authoritative_steps: AuthoritativeStepRanges<StepT>,
615}
616
617impl<StepT: Serialize + Deserialize + Debug + Clone + Display> Display for GameStepResponse<StepT> {
618    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
619        write!(
620            f,
621            "response: {} auth-steps: {}",
622            self.response_header, self.authoritative_steps
623        )
624    }
625}
626
627impl<StepT: Deserialize + Serialize + Debug + Clone + Display> GameStepResponse<StepT> {
628    /// # Errors
629    ///
630    /// `io::Error` // TODO:
631    pub fn to_stream(&self, stream: &mut impl WriteOctetStream) -> io::Result<()> {
632        self.response_header.to_stream(stream)?;
633        self.authoritative_steps.serialize(stream)
634    }
635
636    /// # Errors
637    ///
638    /// `io::Error` // TODO:
639    pub fn from_stream(stream: &mut impl ReadOctetStream) -> io::Result<Self> {
640        Ok(Self {
641            response_header: GameStepResponseHeader::from_stream(stream)?,
642            authoritative_steps: AuthoritativeStepRanges::deserialize(stream)?,
643        })
644    }
645}