1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use std::{any::TypeId, collections::HashMap};

use crate::{
    actors::{actor_builder::ActorBuilder, actor_type::ActorType},
    events::{event_builder::EventBuilder, event_type::EventType},
    packet_reader::PacketReader,
};

/// Contains the shared protocol between Client & Server, with a data that is
/// able to map Event/Actor TypeIds to their representation within specified
/// enums. Also is able to create new Event/Actors using registered Builders,
/// given a specific TypeId.
#[derive(Debug)]
pub struct Manifest<T: EventType, U: ActorType> {
    event_naia_id_count: u16,
    event_builder_map: HashMap<u16, Box<dyn EventBuilder<T>>>,
    event_type_map: HashMap<TypeId, u16>,
    ////
    actor_naia_id_count: u16,
    actor_builder_map: HashMap<u16, Box<dyn ActorBuilder<U>>>,
    actor_type_map: HashMap<TypeId, u16>,
}

impl<T: EventType, U: ActorType> Manifest<T, U> {
    /// Create a new Manifest
    pub fn new() -> Self {
        Manifest {
            event_naia_id_count: 0,
            event_builder_map: HashMap::new(),
            event_type_map: HashMap::new(),
            ///
            actor_naia_id_count: 0,
            actor_builder_map: HashMap::new(),
            actor_type_map: HashMap::new(),
        }
    }

    /// Register an EventBuilder to handle the creation of Event instances
    pub fn register_event(&mut self, event_builder: Box<dyn EventBuilder<T>>) {
        let new_naia_id = self.event_naia_id_count;
        let type_id = event_builder.get_type_id();
        self.event_type_map.insert(type_id, new_naia_id);
        self.event_builder_map.insert(new_naia_id, event_builder);
        self.event_naia_id_count += 1;
    }

    /// Given an Event's TypeId, get a NaiaId (that can be written/read from
    /// packets)
    pub fn get_event_naia_id(&self, type_id: &TypeId) -> u16 {
        let naia_id = self
            .event_type_map
            .get(type_id)
            .expect("hey I should get a TypeId here...");
        return *naia_id;
    }

    /// Creates an Event instance, given a NaiaId and a payload, typically from
    /// an incoming packet
    pub fn create_event(&self, naia_id: u16, reader: &mut PacketReader) -> Option<T> {
        match self.event_builder_map.get(&naia_id) {
            Some(event_builder) => {
                return Some(event_builder.as_ref().build(reader));
            }
            None => {}
        }

        return None;
    }

    /// Register an ActorBuilder to handle the creation of Actor instances
    pub fn register_actor(&mut self, actor_builder: Box<dyn ActorBuilder<U>>) {
        let new_naia_id = self.actor_naia_id_count;
        let type_id = actor_builder.get_type_id();
        self.actor_type_map.insert(type_id, new_naia_id);
        self.actor_builder_map.insert(new_naia_id, actor_builder);
        self.actor_naia_id_count += 1;
    }

    /// Given an Actor's TypeId, get a NaiaId (that can be written/read from
    /// packets)
    pub fn get_actor_naia_id(&self, type_id: &TypeId) -> u16 {
        let naia_id = self
            .actor_type_map
            .get(type_id)
            .expect("hey I should get a TypeId here...");
        return *naia_id;
    }

    /// Creates an Event instance, given a NaiaId and a payload, typically from
    /// an incoming packet
    pub fn create_actor(&self, naia_id: u16, reader: &mut PacketReader) -> Option<U> {
        match self.actor_builder_map.get(&naia_id) {
            Some(actor_builder) => {
                return Some(actor_builder.as_ref().build(reader));
            }
            None => {}
        }

        return None;
    }

    /// Register both an ActorBuilder and an EventBuilder to handle the
    /// creation of both as a Pawn & Command, respectively. Pawns & Commands
    /// should be used for any player-controlled actor that requires clientside
    /// prediction
    pub fn register_pawn(
        &mut self,
        actor_builder: Box<dyn ActorBuilder<U>>,
        event_builder: Box<dyn EventBuilder<T>>,
    ) {
        self.register_actor(actor_builder);
        self.register_event(event_builder);
    }
}