]> git.localhorst.tv Git - blank.git/blob - src/net/Packet.hpp
7dede0d87d61d0cdb9e1d142fd6694350fe9d025
[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 #include <glm/glm.hpp>
9
10
11 namespace blank {
12
13 class Block;
14 class Entity;
15 class EntityState;
16
17 struct Packet {
18
19         static constexpr std::uint32_t TAG = 0xFB1AB1AF;
20
21         static const char *Type2String(std::uint8_t) noexcept;
22
23         struct TControl {
24                 std::uint16_t seq;
25                 std::uint16_t ack;
26                 std::uint32_t hist;
27
28                 // true if this contains an ack for given (remote) seq
29                 bool Acks(std::uint16_t) const noexcept;
30                 std::uint16_t AckBegin() const noexcept { return ack; }
31                 std::uint16_t AckEnd() const noexcept { return ack - std::uint16_t(33); }
32         };
33
34         struct Header {
35                 std::uint32_t tag;
36                 TControl ctrl;
37                 std::uint8_t type;
38                 std::uint8_t reserved1;
39                 std::uint8_t reserved2;
40                 std::uint8_t reserved3;
41         } header;
42
43         static constexpr std::size_t MAX_PAYLOAD_LEN = 500 - sizeof(Header);
44
45         std::uint8_t payload[MAX_PAYLOAD_LEN];
46
47
48         void Tag() noexcept { header.tag = TAG; }
49
50         void Type(std::uint8_t t) noexcept { header.type = t; }
51         std::uint8_t Type() const noexcept { return header.type; }
52         const char *TypeString() const noexcept { return Type2String(Type()); }
53
54
55         struct Payload {
56                 std::size_t length;
57                 std::uint8_t *data;
58
59                 /// WARNING: do not use these if the data doesn not
60                 ///          point into a real packet's payload
61                 const Packet &GetPacket() const noexcept {
62                         return *reinterpret_cast<const Packet *>(data - sizeof(Header));
63                 }
64                 const Header &GetHeader() const noexcept {
65                         return GetPacket().header;
66                 }
67                 std::uint16_t Seq() const noexcept {
68                         return GetHeader().ctrl.seq;
69                 }
70
71                 template<class T>
72                 void Write(const T &, size_t off) noexcept;
73                 template<class T>
74                 void Read(T &, size_t off) const noexcept;
75
76                 void Write(const glm::quat &, size_t off) noexcept;
77                 void Read(glm::quat &, size_t off) const noexcept;
78                 void Write(const EntityState &, size_t off) noexcept;
79                 void Read(EntityState &, size_t off) const noexcept;
80                 void Write(const EntityState &, const glm::ivec3 &, size_t off) noexcept;
81                 void Read(EntityState &, const glm::ivec3 &, size_t off) const noexcept;
82
83                 void WriteString(const std::string &src, std::size_t off, std::size_t maxlen) noexcept;
84                 void ReadString(std::string &dst, std::size_t off, std::size_t maxlen) const noexcept;
85
86                 void WritePackB(const glm::ivec3 &, size_t off) noexcept;
87                 void ReadPackB(glm::ivec3 &, size_t off) const noexcept;
88
89                 void WritePackN(float, size_t off) noexcept;
90                 void ReadPackN(float &, size_t off) const noexcept;
91                 void WritePackN(const glm::vec3 &, size_t off) noexcept;
92                 void ReadPackN(glm::vec3 &, size_t off) const noexcept;
93
94                 void WritePackU(float, size_t off) noexcept;
95                 void ReadPackU(float &, size_t off) const noexcept;
96                 void WritePackU(const glm::vec3 &, size_t off) noexcept;
97                 void ReadPackU(glm::vec3 &, size_t off) const noexcept;
98         };
99
100         struct Ping : public Payload {
101                 static constexpr std::uint8_t TYPE = 0;
102                 static constexpr std::size_t MAX_LEN = 0;
103         };
104
105         struct Login : public Payload {
106                 static constexpr std::uint8_t TYPE = 1;
107                 static constexpr std::size_t MAX_LEN = 32;
108
109                 void WritePlayerName(const std::string &) noexcept;
110                 void ReadPlayerName(std::string &) const noexcept;
111         };
112
113         struct Join : public Payload {
114                 static constexpr std::uint8_t TYPE = 2;
115                 static constexpr std::size_t MAX_LEN = 78;
116
117                 void WritePlayer(const Entity &) noexcept;
118                 void ReadPlayerID(std::uint32_t &) const noexcept;
119                 void ReadPlayerState(EntityState &) const noexcept;
120                 void WriteWorldName(const std::string &) noexcept;
121                 void ReadWorldName(std::string &) const noexcept;
122         };
123
124         struct Part : public Payload {
125                 static constexpr std::uint8_t TYPE = 3;
126                 static constexpr std::size_t MAX_LEN = 0;
127         };
128
129         struct PlayerUpdate : public Payload {
130                 static constexpr std::uint8_t TYPE = 4;
131                 static constexpr std::size_t MAX_LEN = 50;
132
133                 void WritePredictedState(const EntityState &) noexcept;
134                 void ReadPredictedState(EntityState &) const noexcept;
135                 void WriteMovement(const glm::vec3 &) noexcept;
136                 void ReadMovement(glm::vec3 &) const noexcept;
137                 void WriteActions(std::uint8_t) noexcept;
138                 void ReadActions(std::uint8_t &) const noexcept;
139                 void WriteSlot(std::uint8_t) noexcept;
140                 void ReadSlot(std::uint8_t &) const noexcept;
141         };
142
143         struct SpawnEntity : public Payload {
144                 static constexpr std::uint8_t TYPE = 5;
145                 static constexpr std::size_t MAX_LEN = 110;
146
147                 void WriteEntity(const Entity &) noexcept;
148                 void ReadEntityID(std::uint32_t &) const noexcept;
149                 void ReadModelID(std::uint32_t &) const noexcept;
150                 void ReadEntity(Entity &) const noexcept;
151         };
152
153         struct DespawnEntity : public Payload {
154                 static constexpr std::uint8_t TYPE = 6;
155                 static constexpr std::size_t MAX_LEN = 4;
156
157                 void WriteEntityID(std::uint32_t) noexcept;
158                 void ReadEntityID(std::uint32_t &) const noexcept;
159         };
160
161         struct EntityUpdate : public Payload {
162                 static constexpr std::uint8_t TYPE = 7;
163                 static constexpr std::size_t MAX_LEN = 460;
164
165                 static constexpr std::uint32_t MAX_ENTITIES = 12;
166                 static constexpr std::size_t GetSize(std::uint32_t num) noexcept {
167                         return 16 + (num * 37);
168                 }
169
170                 void WriteEntityCount(std::uint32_t) noexcept;
171                 void ReadEntityCount(std::uint32_t &) const noexcept;
172                 void WriteChunkBase(const glm::ivec3 &) noexcept;
173                 void ReadChunkBase(glm::ivec3 &) const noexcept;
174
175                 void WriteEntity(const Entity &, const glm::ivec3 &, std::uint32_t) noexcept;
176                 void ReadEntityID(std::uint32_t &, std::uint32_t) const noexcept;
177                 void ReadEntityState(EntityState &, const glm::ivec3 &, std::uint32_t) const noexcept;
178         };
179
180         struct PlayerCorrection : public Payload {
181                 static constexpr std::uint8_t TYPE = 8;
182                 static constexpr std::size_t MAX_LEN = 44;
183
184                 void WritePacketSeq(std::uint16_t) noexcept;
185                 void ReadPacketSeq(std::uint16_t &) const noexcept;
186                 void WritePlayer(const Entity &) noexcept;
187                 void ReadPlayerState(EntityState &) const noexcept;
188         };
189
190         struct ChunkBegin : public Payload {
191                 static constexpr std::uint8_t TYPE = 9;
192                 static constexpr std::size_t MAX_LEN = 24;
193
194                 void WriteTransmissionId(std::uint32_t) noexcept;
195                 void ReadTransmissionId(std::uint32_t &) const noexcept;
196                 void WriteFlags(std::uint32_t) noexcept;
197                 void ReadFlags(std::uint32_t &) const noexcept;
198                 void WriteChunkCoords(const glm::ivec3 &) noexcept;
199                 void ReadChunkCoords(glm::ivec3 &) const noexcept;
200                 void WriteDataSize(std::uint32_t) noexcept;
201                 void ReadDataSize(std::uint32_t &) const noexcept;
202         };
203
204         struct ChunkData : public Payload {
205                 static constexpr std::uint8_t TYPE = 10;
206                 static constexpr std::size_t MAX_LEN = MAX_PAYLOAD_LEN;
207                 static constexpr std::size_t MAX_DATA_LEN = MAX_LEN - 12;
208
209                 static constexpr std::size_t GetSize(std::size_t data_len) noexcept {
210                         return data_len + 12;
211                 }
212
213                 void WriteTransmissionId(std::uint32_t) noexcept;
214                 void ReadTransmissionId(std::uint32_t &) const noexcept;
215                 void WriteDataOffset(std::uint32_t) noexcept;
216                 void ReadDataOffset(std::uint32_t &) const noexcept;
217                 void WriteDataSize(std::uint32_t) noexcept;
218                 void ReadDataSize(std::uint32_t &) const noexcept;
219                 void WriteData(const std::uint8_t *, std::size_t len) noexcept;
220                 void ReadData(std::uint8_t *, std::size_t maxlen) const noexcept;
221         };
222
223         struct BlockUpdate : public Payload {
224                 static constexpr std::uint8_t TYPE = 11;
225                 static constexpr std::size_t MAX_LEN = 484;
226
227                 static constexpr std::uint32_t MAX_BLOCKS = 78;
228                 static constexpr std::size_t GetSize(std::uint32_t num) noexcept {
229                         return 16 + (num * 6);
230                 }
231
232                 void WriteChunkCoords(const glm::ivec3 &) noexcept;
233                 void ReadChunkCoords(glm::ivec3 &) const noexcept;
234                 void WriteBlockCount(std::uint32_t) noexcept;
235                 void ReadBlockCount(std::uint32_t &) const noexcept;
236
237                 void WriteIndex(std::uint16_t, std::uint32_t) noexcept;
238                 void ReadIndex(std::uint16_t &, std::uint32_t) const noexcept;
239                 void WriteBlock(const Block &, std::uint32_t) noexcept;
240                 void ReadBlock(Block &, std::uint32_t) const noexcept;
241         };
242
243         struct Message : public Payload {
244                 static constexpr std::uint8_t TYPE = 12;
245                 static constexpr std::size_t MAX_LEN = 455;
246
247                 static constexpr std::size_t MAX_MESSAGE_LEN = 450;
248                 static std::size_t GetSize(const std::string &msg) noexcept {
249                         return 5 + std::min(msg.size() + 1, MAX_MESSAGE_LEN);
250                 }
251
252                 void WriteType(std::uint8_t) noexcept;
253                 void ReadType(std::uint8_t &) const noexcept;
254                 void WriteReferral(std::uint32_t) noexcept;
255                 void ReadReferral(std::uint32_t &) const noexcept;
256                 void WriteMessage(const std::string &) noexcept;
257                 void ReadMessage(std::string &) const noexcept;
258         };
259
260
261         template<class PayloadType>
262         PayloadType As() {
263                 PayloadType result;
264                 result.length = PayloadType::MAX_LEN;
265                 result.data = &payload[0];
266                 return result;
267         }
268
269         template<class PayloadType>
270         static PayloadType As(const UDPpacket &pack) {
271                 PayloadType result;
272                 result.length = std::min(pack.len - sizeof(Header), PayloadType::MAX_LEN);
273                 result.data = pack.data + sizeof(Header);
274                 return result;
275         }
276
277         template<class PayloadType>
278         static PayloadType Make(UDPpacket &udp_pack) {
279                 Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
280                 pack.Tag();
281                 pack.Type(PayloadType::TYPE);
282
283                 udp_pack.len = sizeof(Header) + PayloadType::MAX_LEN;
284
285                 PayloadType result;
286                 result.length = PayloadType::MAX_LEN;
287                 result.data = pack.payload;
288                 return result;
289         }
290
291 };
292
293 }
294
295 #endif