-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPacketHelper.h
228 lines (191 loc) · 8.08 KB
/
PacketHelper.h
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#pragma once
#include <vector>
#include <iostream>
#include <sstream>
#include "enet/enet.h"
#define INVALID_INT -1
#define INVALID_STR "INVALID_STR"
namespace Samurai
{
enum PacketType // used in cases when you want to send data, on the receiving side you can use the PacketType to identify what data should be expected in the receieved packet
{
// Core
PROVIDE_QUICK_RESPONSE,
PROVIDE_QUICK_RESPONSE_MESSAGE,
// Example
PROVIDE_WELCOME_MESSAGE
};
enum QuickResponseType // used in cases when you dont want to send extra data, helper functions exist for sending these easily
{
// Example
ACK_WELCOME_MESSAGE
};
struct Packet
{
int type; // Packet identifier
std::vector<char> data; // Flexible payload
bool valid = true; // if the packet was (de)serialized properly
// turn outgoing data into a byte array which is compatible with enet
std::vector<char> serialize() const
{
std::vector<char> buffer(sizeof(int) + data.size());
memcpy(buffer.data(), &type, sizeof(int));
memcpy(buffer.data() + sizeof(int), data.data(), data.size());
return buffer;
}
// turn recieved byte array back into data
static Packet deserialize(const char* buffer, size_t length)
{
Packet packet;
if (length < sizeof(int)) { std::cerr << "Invalid packet size." << std::endl; packet.valid = false; return packet; }
memcpy(&packet.type, buffer, sizeof(int));
packet.data.assign(buffer + sizeof(int), buffer + length);
return packet;
}
};
// Append an integer to a vector<char> used in a Packet
void appendInt(std::vector<char>& buffer, int value)
{
buffer.insert(buffer.end(), reinterpret_cast<const char*>(&value),
reinterpret_cast<const char*>(&value) + sizeof(int));
}
// Extract an integer from a vector<char> used in a Packet
int extractInt(const std::vector<char>& buffer, size_t& offset)
{
if (offset + sizeof(int) > buffer.size()) { std::cerr << "Buffer underflow while extracting int." << std::endl; return INVALID_INT; }
int value;
memcpy(&value, buffer.data() + offset, sizeof(int));
offset += sizeof(int);
return value;
}
// Append IP address (as enet_uint32)
void appendUInt32(std::vector<char>& buffer, enet_uint32 value)
{
buffer.insert(buffer.end(),
reinterpret_cast<const char*>(&value),
reinterpret_cast<const char*>(&value) + sizeof(enet_uint32));
}
// Extract a uint32 from a vector<char> used in a Packet
unsigned int extractUInt32(const std::vector<char>& buffer, size_t& offset)
{
if (offset + sizeof(unsigned int) > buffer.size()) { std::cerr << "Buffer underflow while extracting unsigned int." << std::endl; return INVALID_INT; }
unsigned int value;
memcpy(&value, buffer.data() + offset, sizeof(unsigned int));
offset += sizeof(unsigned int);
return value;
}
// Append a uint16 to a vector<char> used in a Packet
void appendUInt16(std::vector<char>& buffer, enet_uint16 value)
{
buffer.insert(buffer.end(),
reinterpret_cast<const char*>(&value),
reinterpret_cast<const char*>(&value) + sizeof(enet_uint16));
}
// Extract a uint16_t from a vector<char> used in a Packet
unsigned short extractUInt16(const std::vector<char>& buffer, size_t& offset)
{
if (offset + sizeof(unsigned short) > buffer.size()) { std::cerr << "Buffer underflow while extracting unsigned short." << std::endl; return INVALID_INT; }
unsigned short value;
memcpy(&value, buffer.data() + offset, sizeof(unsigned short));
offset += sizeof(unsigned short);
return value;
}
// Append an ENetAddress (enet_uint32) and port (enet_uint16) to a vector<char> used in a Packet
void appendAddress(std::vector<char>& buffer, ENetAddress addr)
{
appendUInt32(buffer, addr.host);
appendUInt16(buffer, addr.port);
}
// Append an ENetAddress (enet_uint32) and port (enet_uint16) to a vector<char> used in a Packet
ENetAddress extractAddress(std::vector<char>& buffer, size_t& offset)
{
ENetAddress addr;
addr.host = extractUInt32(buffer, offset);
if (addr.host == INVALID_INT) { std::cerr << "Buffer underflow while extracting uint32 for address." << std::endl; return addr; }
addr.port = extractUInt16(buffer, offset);
if (addr.port == INVALID_INT) { std::cerr << "Buffer underflow while extracting uint16 for address." << std::endl; return addr; }
return addr;
}
// Append a string to a vector<char> used in a Packet
void appendString(std::vector<char>& buffer, const std::string& value)
{
int length = value.size();
appendInt(buffer, length);
buffer.insert(buffer.end(), value.begin(), value.end());
}
// Extract a string from a vector<char> used in a Packet
std::string extractString(const std::vector<char>& buffer, size_t& offset)
{
int length = extractInt(buffer, offset);
if (offset + length > buffer.size()) { std::cerr << "Buffer underflow while extracting string." << std::endl; return INVALID_STR; }
std::string value(buffer.begin() + offset, buffer.begin() + offset + length);
offset += length;
return value;
}
void sendNow(Packet& packet, ENetPeer* Client, ENetPacketFlag Flag = ENET_PACKET_FLAG_RELIABLE)
{
if (!Client) return;
auto serializedData = packet.serialize();
ENetPacket* enetPacket = enet_packet_create(serializedData.data(), serializedData.size(), Flag);
enet_peer_send(Client, 0, enetPacket);
enet_host_flush(Client->host);
}
void sendBroadcastNow(std::vector<ENetPeer*> connections, Packet& packet, ENetPacketFlag Flag = ENET_PACKET_FLAG_RELIABLE)
{
if (connections.empty()) return;
for (ENetPeer* connection : connections)
{
if (!connection) continue;
sendNow(packet, connection, Flag);
}
}
void sendQuickResponseNow(ENetPeer* Client, QuickResponseType Reason, ENetPacketFlag Flag = ENET_PACKET_FLAG_RELIABLE)
{
Packet packet;
packet.type = PROVIDE_QUICK_RESPONSE;
appendInt(packet.data, Reason);
sendNow(packet, Client, Flag);
}
void sendBroadcastQuickResponseNow(std::vector<ENetPeer*> connections, QuickResponseType Reason, ENetPacketFlag Flag = ENET_PACKET_FLAG_RELIABLE)
{
if (connections.empty()) return;
for (ENetPeer* connection : connections)
{
if (!connection) continue;
Packet packet;
packet.type = PROVIDE_QUICK_RESPONSE;
appendInt(packet.data, Reason);
sendNow(packet, connection, Flag);
}
}
void sendBroadcastQuickResponseMessageNow(std::vector<ENetPeer*> connections, std::string Reason, ENetPacketFlag Flag = ENET_PACKET_FLAG_RELIABLE)
{
if (connections.empty()) return;
for (ENetPeer* connection : connections)
{
if (!connection) continue;
Packet packet;
packet.type = PROVIDE_QUICK_RESPONSE_MESSAGE;
appendString(packet.data, Reason);
sendNow(packet, connection, Flag);
}
}
std::string ipToString(enet_uint32 ip)
{
// bitshift each byte then format them into a string
unsigned char byte1 = (ip >> 24) & 0xFF;
unsigned char byte2 = (ip >> 16) & 0xFF;
unsigned char byte3 = (ip >> 8) & 0xFF;
unsigned char byte4 = ip & 0xFF;
std::ostringstream ipString;
ipString << static_cast<int>(byte4) << "."
<< static_cast<int>(byte2) << "."
<< static_cast<int>(byte3) << "."
<< static_cast<int>(byte1);
return ipString.str();
}
bool areAdderessesMatching(ENetAddress addrA, ENetAddress addrB)
{
return addrA.host == addrB.host && addrA.port == addrB.port;
}
}