]> git.localhorst.tv Git - blank.git/blob - src/net/Packet.hpp
more packet introspection from payload
[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 Entity;
14 class EntityState;
15
16 struct Packet {
17
18         static constexpr std::uint32_t TAG = 0xFB1AB1AF;
19
20         static const char *Type2String(std::uint8_t) noexcept;
21
22         struct TControl {
23                 std::uint16_t seq;
24                 std::uint16_t ack;
25                 std::uint32_t hist;
26
27                 // true if this contains an ack for given (remote) seq
28                 bool Acks(std::uint16_t) const noexcept;
29                 std::uint16_t AckBegin() const noexcept { return ack; }
30                 std::uint16_t AckEnd() const noexcept { return ack - std::uint16_t(33); }
31         };
32
33         struct Header {
34                 std::uint32_t tag;
35                 TControl ctrl;
36                 std::uint8_t type;
37                 std::uint8_t reserved1;
38                 std::uint8_t reserved2;
39                 std::uint8_t reserved3;
40         } header;
41
42         static constexpr std::size_t MAX_PAYLOAD_LEN = 500 - sizeof(Header);
43
44         std::uint8_t payload[MAX_PAYLOAD_LEN];
45
46
47         void Tag() noexcept { header.tag = TAG; }
48
49         void Type(std::uint8_t t) noexcept { header.type = t; }
50         std::uint8_t Type() const noexcept { return header.type; }
51         const char *TypeString() const noexcept { return Type2String(Type()); }
52
53
54         struct Payload {
55                 std::size_t length;
56                 std::uint8_t *data;
57
58                 /// WARNING: do not use these if the data doesn not
59                 ///          point into a real packet's payload
60                 const Packet &GetPacket() const noexcept {
61                         return *reinterpret_cast<const Packet *>(data - sizeof(Header));
62                 }
63                 const Header &GetHeader() const noexcept {
64                         return GetPacket().header;
65                 }
66                 std::uint16_t Seq() const noexcept {
67                         return GetHeader().ctrl.seq;
68                 }
69
70                 template<class T>
71                 void Write(const T &, size_t off) noexcept;
72                 template<class T>
73                 void Read(T &, size_t off) const noexcept;
74
75                 void WriteString(const std::string &src, std::size_t off, std::size_t maxlen) noexcept;
76                 void ReadString(std::string &dst, std::size_t off, std::size_t maxlen) const noexcept;
77         };
78
79         struct Ping : public Payload {
80                 static constexpr std::uint8_t TYPE = 0;
81                 static constexpr std::size_t MAX_LEN = 0;
82         };
83
84         struct Login : public Payload {
85                 static constexpr std::uint8_t TYPE = 1;
86                 static constexpr std::size_t MAX_LEN = 32;
87
88                 void WritePlayerName(const std::string &) noexcept;
89                 void ReadPlayerName(std::string &) const noexcept;
90         };
91
92         struct Join : public Payload {
93                 static constexpr std::uint8_t TYPE = 2;
94                 static constexpr std::size_t MAX_LEN = 100;
95
96                 void WritePlayer(const Entity &) noexcept;
97                 void ReadPlayerID(std::uint32_t &) const noexcept;
98                 void ReadPlayerState(EntityState &) const noexcept;
99                 void WriteWorldName(const std::string &) noexcept;
100                 void ReadWorldName(std::string &) const noexcept;
101         };
102
103         struct Part : public Payload {
104                 static constexpr std::uint8_t TYPE = 3;
105                 static constexpr std::size_t MAX_LEN = 0;
106         };
107
108         struct PlayerUpdate : public Payload {
109                 static constexpr std::uint8_t TYPE = 4;
110                 static constexpr std::size_t MAX_LEN = 64;
111
112                 void WritePlayer(const Entity &) noexcept;
113                 void ReadPlayerState(EntityState &) const noexcept;
114         };
115
116         struct SpawnEntity : public Payload {
117                 static constexpr std::uint8_t TYPE = 5;
118                 static constexpr std::size_t MAX_LEN = 132;
119
120                 void WriteEntity(const Entity &) noexcept;
121                 void ReadEntityID(std::uint32_t &) const noexcept;
122                 void ReadSkeletonID(std::uint32_t &) const noexcept;
123                 void ReadEntity(Entity &) const noexcept;
124         };
125
126         struct DespawnEntity : public Payload {
127                 static constexpr std::uint8_t TYPE = 6;
128                 static constexpr std::size_t MAX_LEN = 4;
129
130                 void WriteEntityID(std::uint32_t) noexcept;
131                 void ReadEntityID(std::uint32_t &) const noexcept;
132         };
133
134         struct EntityUpdate : public Payload {
135                 static constexpr std::uint8_t TYPE = 7;
136                 static constexpr std::size_t MAX_LEN = 452;
137
138                 static constexpr std::uint32_t MAX_ENTITIES = 7;
139                 static constexpr std::size_t GetSize(std::uint32_t num) noexcept {
140                         return 4 + (num * 64);
141                 }
142
143                 void WriteEntityCount(std::uint32_t) noexcept;
144                 void ReadEntityCount(std::uint32_t &) const noexcept;
145
146                 void WriteEntity(const Entity &, std::uint32_t) noexcept;
147                 void ReadEntityID(std::uint32_t &, std::uint32_t) const noexcept;
148                 void ReadEntityState(EntityState &, std::uint32_t) const noexcept;
149         };
150
151         struct PlayerCorrection : public Payload {
152                 static constexpr std::uint8_t TYPE = 8;
153                 static constexpr std::size_t MAX_LEN = 66;
154
155                 void WritePacketSeq(std::uint16_t) noexcept;
156                 void ReadPacketSeq(std::uint16_t &) const noexcept;
157                 void WritePlayer(const Entity &) noexcept;
158                 void ReadPlayerState(EntityState &) const noexcept;
159         };
160
161         struct ChunkBegin : public Payload {
162                 static constexpr std::uint8_t TYPE = 9;
163                 static constexpr std::size_t MAX_LEN = 24;
164
165                 void WriteTransmissionId(std::uint32_t) noexcept;
166                 void ReadTransmissionId(std::uint32_t &) const noexcept;
167                 void WriteFlags(std::uint32_t) noexcept;
168                 void ReadFlags(std::uint32_t &) const noexcept;
169                 void WriteChunkCoords(const glm::ivec3 &) noexcept;
170                 void ReadChunkCoords(glm::ivec3 &) const noexcept;
171                 void WriteDataSize(std::uint32_t) noexcept;
172                 void ReadDataSize(std::uint32_t &) const noexcept;
173         };
174
175         struct ChunkData : public Payload {
176                 static constexpr std::uint8_t TYPE = 10;
177                 static constexpr std::size_t MAX_LEN = MAX_PAYLOAD_LEN;
178                 static constexpr std::size_t MAX_DATA_LEN = MAX_LEN - 12;
179
180                 void WriteTransmissionId(std::uint32_t) noexcept;
181                 void ReadTransmissionId(std::uint32_t &) const noexcept;
182                 void WriteDataOffset(std::uint32_t) noexcept;
183                 void ReadDataOffset(std::uint32_t &) const noexcept;
184                 void WriteDataSize(std::uint32_t) noexcept;
185                 void ReadDataSize(std::uint32_t &) const noexcept;
186                 void WriteData(const std::uint8_t *, std::size_t len) noexcept;
187                 void ReadData(std::uint8_t *, std::size_t maxlen) const noexcept;
188         };
189
190
191         template<class PayloadType>
192         PayloadType As() {
193                 PayloadType result;
194                 result.length = PayloadType::MAX_LEN;
195                 result.data = &payload[0];
196                 return result;
197         }
198
199         template<class PayloadType>
200         static PayloadType As(const UDPpacket &pack) {
201                 PayloadType result;
202                 result.length = std::min(pack.len - sizeof(Header), PayloadType::MAX_LEN);
203                 result.data = pack.data + sizeof(Header);
204                 return result;
205         }
206
207         template<class PayloadType>
208         static PayloadType Make(UDPpacket &udp_pack) {
209                 Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
210                 pack.Tag();
211                 pack.Type(PayloadType::TYPE);
212
213                 udp_pack.len = sizeof(Header) + PayloadType::MAX_LEN;
214
215                 PayloadType result;
216                 result.length = PayloadType::MAX_LEN;
217                 result.data = pack.payload;
218                 return result;
219         }
220
221 };
222
223 }
224
225 #endif