]> git.localhorst.tv Git - blank.git/blob - src/net/Packet.hpp
better control over entity update transmission
[blank.git] / src / net / Packet.hpp
1 #ifndef BLANK_NET_PACKET_HPP_
2 #define BLANK_NET_PACKET_HPP_
3
4 #include <cstdint>
5 #include <ostream>
6 #include <string>
7 #include <SDL_net.h>
8
9
10 namespace blank {
11
12 class Entity;
13
14 struct Packet {
15
16         static constexpr std::uint32_t TAG = 0xFB1AB1AF;
17
18         static const char *Type2String(std::uint8_t) noexcept;
19
20         struct TControl {
21                 std::uint16_t seq;
22                 std::uint16_t ack;
23                 std::uint32_t hist;
24
25                 // true if this contains an ack for given (remote) seq
26                 bool Acks(std::uint16_t) const noexcept;
27                 std::uint16_t AckBegin() const noexcept { return ack; }
28                 std::uint16_t AckEnd() const noexcept { return ack + std::uint16_t(33); }
29         };
30
31         struct Header {
32                 std::uint32_t tag;
33                 TControl ctrl;
34                 std::uint8_t type;
35                 std::uint8_t reserved1;
36                 std::uint8_t reserved2;
37                 std::uint8_t reserved3;
38         } header;
39
40         static constexpr std::size_t MAX_PAYLOAD_LEN = 500 - sizeof(Header);
41
42         std::uint8_t payload[MAX_PAYLOAD_LEN];
43
44
45         void Tag() noexcept { header.tag = TAG; }
46
47         void Type(std::uint8_t t) noexcept { header.type = t; }
48         std::uint8_t Type() const noexcept { return header.type; }
49         const char *TypeString() const noexcept { return Type2String(Type()); }
50
51
52         struct Payload {
53                 std::size_t length;
54                 std::uint8_t *data;
55
56                 std::uint16_t Seq() const noexcept {
57                         return reinterpret_cast<const Packet *>(data - sizeof(Header))->header.ctrl.seq;
58                 }
59
60                 template<class T>
61                 void Write(const T &, size_t off) noexcept;
62                 template<class T>
63                 void Read(T &, size_t off) const noexcept;
64
65                 void WriteString(const std::string &src, std::size_t off, std::size_t maxlen) noexcept;
66                 void ReadString(std::string &dst, std::size_t off, std::size_t maxlen) const noexcept;
67         };
68
69         struct Ping : public Payload {
70                 static constexpr std::uint8_t TYPE = 0;
71                 static constexpr std::size_t MAX_LEN = 0;
72         };
73
74         struct Login : public Payload {
75                 static constexpr std::uint8_t TYPE = 1;
76                 static constexpr std::size_t MAX_LEN = 32;
77
78                 void WritePlayerName(const std::string &) noexcept;
79                 void ReadPlayerName(std::string &) const noexcept;
80         };
81
82         struct Join : public Payload {
83                 static constexpr std::uint8_t TYPE = 2;
84                 static constexpr std::size_t MAX_LEN = 100;
85
86                 void WritePlayer(const Entity &) noexcept;
87                 void ReadPlayerID(std::uint32_t &) const noexcept;
88                 void ReadPlayer(Entity &) const noexcept;
89                 void WriteWorldName(const std::string &) noexcept;
90                 void ReadWorldName(std::string &) const noexcept;
91         };
92
93         struct Part : public Payload {
94                 static constexpr std::uint8_t TYPE = 3;
95                 static constexpr std::size_t MAX_LEN = 0;
96         };
97
98         struct PlayerUpdate : public Payload {
99                 static constexpr std::uint8_t TYPE = 4;
100                 static constexpr std::size_t MAX_LEN = 64;
101
102                 void WritePlayer(const Entity &) noexcept;
103                 void ReadPlayer(Entity &) const noexcept;
104         };
105
106         struct SpawnEntity : public Payload {
107                 static constexpr std::uint8_t TYPE = 5;
108                 static constexpr std::size_t MAX_LEN = 132;
109
110                 void WriteEntity(const Entity &) noexcept;
111                 void ReadEntityID(std::uint32_t &) const noexcept;
112                 void ReadSkeletonID(std::uint32_t &) const noexcept;
113                 void ReadEntity(Entity &) const noexcept;
114         };
115
116         struct DespawnEntity : public Payload {
117                 static constexpr std::uint8_t TYPE = 6;
118                 static constexpr std::size_t MAX_LEN = 4;
119
120                 void WriteEntityID(std::uint32_t) noexcept;
121                 void ReadEntityID(std::uint32_t &) const noexcept;
122         };
123
124         struct EntityUpdate : public Payload {
125                 static constexpr std::uint8_t TYPE = 7;
126                 static constexpr std::size_t MAX_LEN = 452;
127
128                 static constexpr std::uint32_t MAX_ENTITIES = 7;
129                 static constexpr std::size_t GetSize(std::uint32_t num) noexcept {
130                         return 4 + (num * 64);
131                 }
132
133                 void WriteEntityCount(std::uint32_t) noexcept;
134                 void ReadEntityCount(std::uint32_t &) const noexcept;
135
136                 void WriteEntity(const Entity &, std::uint32_t) noexcept;
137                 void ReadEntityID(std::uint32_t &, std::uint32_t) const noexcept;
138                 void ReadEntity(Entity &, std::uint32_t) const noexcept;
139         };
140
141
142         template<class PayloadType>
143         PayloadType As() {
144                 PayloadType result;
145                 result.length = PayloadType::MAX_LEN;
146                 result.data = &payload[0];
147                 return result;
148         }
149
150         template<class PayloadType>
151         static PayloadType As(const UDPpacket &pack) {
152                 PayloadType result;
153                 result.length = std::min(pack.len - sizeof(Header), PayloadType::MAX_LEN);
154                 result.data = pack.data + sizeof(Header);
155                 return result;
156         }
157
158         template<class PayloadType>
159         static PayloadType Make(UDPpacket &udp_pack) {
160                 Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
161                 pack.Tag();
162                 pack.Type(PayloadType::TYPE);
163
164                 udp_pack.len = sizeof(Header) + PayloadType::MAX_LEN;
165
166                 PayloadType result;
167                 result.length = PayloadType::MAX_LEN;
168                 result.data = pack.payload;
169                 return result;
170         }
171
172 };
173
174 }
175
176 #endif