1 |
|
|
/* |
2 |
|
|
* The ManaPlus Client |
3 |
|
|
* Copyright (C) 2004-2009 The Mana World Development Team |
4 |
|
|
* Copyright (C) 2009-2010 The Mana Developers |
5 |
|
|
* Copyright (C) 2011-2019 The ManaPlus Developers |
6 |
|
|
* Copyright (C) 2019-2021 Andrei Karas |
7 |
|
|
* |
8 |
|
|
* This file is part of The ManaPlus Client. |
9 |
|
|
* |
10 |
|
|
* This program is free software; you can redistribute it and/or modify |
11 |
|
|
* it under the terms of the GNU General Public License as published by |
12 |
|
|
* the Free Software Foundation; either version 2 of the License, or |
13 |
|
|
* any later version. |
14 |
|
|
* |
15 |
|
|
* This program is distributed in the hope that it will be useful, |
16 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 |
|
|
* GNU General Public License for more details. |
19 |
|
|
* |
20 |
|
|
* You should have received a copy of the GNU General Public License |
21 |
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
22 |
|
|
*/ |
23 |
|
|
|
24 |
|
|
#include "net/messageout.h" |
25 |
|
|
|
26 |
|
|
#include "logger.h" |
27 |
|
|
|
28 |
|
|
#include "net/net.h" |
29 |
|
|
#include "net/packetcounters.h" |
30 |
|
|
|
31 |
|
|
#include "utils/stringutils.h" |
32 |
|
|
|
33 |
|
|
PRAGMA48(GCC diagnostic push) |
34 |
|
|
PRAGMA48(GCC diagnostic ignored "-Wshadow") |
35 |
|
|
#include <SDL_endian.h> |
36 |
|
|
PRAGMA48(GCC diagnostic pop) |
37 |
|
|
|
38 |
|
|
#include "debug.h" |
39 |
|
|
|
40 |
|
|
#ifndef SDL_BIG_ENDIAN |
41 |
|
|
#error missing SDL_endian.h |
42 |
|
|
#endif // SDL_BYTEORDER |
43 |
|
|
|
44 |
|
|
extern int itemIdLen; |
45 |
|
|
|
46 |
|
|
namespace Net |
47 |
|
|
{ |
48 |
|
|
|
49 |
|
|
MessageOut::MessageOut(const int16_t id) : |
50 |
|
|
mData(nullptr), |
51 |
|
|
mDataSize(0), |
52 |
|
|
mPos(0), |
53 |
|
|
mId(id), |
54 |
|
|
mIgnore(false) |
55 |
|
|
{ |
56 |
|
|
PacketCounters::incOutPackets(); |
57 |
|
|
IGNOREDEBUGLOG; |
58 |
|
|
DEBUGLOG2("Send packet", 0, "MessageOut"); |
59 |
|
|
} |
60 |
|
|
|
61 |
|
|
void MessageOut::writeInt8(const int8_t value, const char *const str) |
62 |
|
|
{ |
63 |
|
|
expand(1); |
64 |
|
|
mData[mPos] = value; |
65 |
|
|
DEBUGLOG2("writeInt8: " + toStringPrint(CAST_U32( |
66 |
|
|
CAST_U8(value))), |
67 |
|
|
mPos, str); |
68 |
|
|
mPos += 1; |
69 |
|
|
} |
70 |
|
|
|
71 |
|
|
void MessageOut::writeInt16(const int16_t value, const char *const str) |
72 |
|
|
{ |
73 |
|
|
expand(2); |
74 |
|
|
#if SDL_BYTEORDER == SDL_BIG_ENDIAN |
75 |
|
|
int16_t swap = SDL_Swap16(value); |
76 |
|
|
memcpy(mData + CAST_SIZE(mPos), &swap, sizeof(int16_t)); |
77 |
|
|
#else // SDL_BYTEORDER == SDL_BIG_ENDIAN |
78 |
|
|
|
79 |
|
|
memcpy(mData + CAST_SIZE(mPos), &value, sizeof(int16_t)); |
80 |
|
|
#endif // SDL_BYTEORDER == SDL_BIG_ENDIAN |
81 |
|
|
|
82 |
|
|
DEBUGLOG2("writeInt16: " + toStringPrint(CAST_U32( |
83 |
|
|
CAST_U16(value))), |
84 |
|
|
mPos, str); |
85 |
|
|
mPos += 2; |
86 |
|
|
} |
87 |
|
|
|
88 |
|
|
void MessageOut::writeInt32(const int32_t value, const char *const str) |
89 |
|
|
{ |
90 |
|
|
DEBUGLOG2("writeInt32: " + toStringPrint(CAST_U32(value)), |
91 |
|
|
mPos, str); |
92 |
|
|
expand(4); |
93 |
|
|
#if SDL_BYTEORDER == SDL_BIG_ENDIAN |
94 |
|
|
int32_t swap = SDL_Swap32(value); |
95 |
|
|
memcpy(mData + CAST_SIZE(mPos), &swap, sizeof(int32_t)); |
96 |
|
|
#else // SDL_BYTEORDER == SDL_BIG_ENDIAN |
97 |
|
|
|
98 |
|
|
memcpy(mData + CAST_SIZE(mPos), &value, sizeof(int32_t)); |
99 |
|
|
#endif // SDL_BYTEORDER == SDL_BIG_ENDIAN |
100 |
|
|
|
101 |
|
|
mPos += 4; |
102 |
|
|
} |
103 |
|
|
|
104 |
|
|
void MessageOut::writeItemId(const int32_t value, |
105 |
|
|
const char *const str) |
106 |
|
|
{ |
107 |
|
|
if (itemIdLen == 2) |
108 |
|
|
writeInt16(CAST_S16(value), str); |
109 |
|
|
else |
110 |
|
|
writeInt32(value, str); |
111 |
|
|
} |
112 |
|
|
|
113 |
|
|
void MessageOut::writeInt64(const int64_t value, const char *const str) |
114 |
|
|
{ |
115 |
|
|
DEBUGLOG2("writeInt64: " + toStringPrint(CAST_U32(value)), |
116 |
|
|
mPos, str); |
117 |
|
|
expand(8); |
118 |
|
|
#if SDL_BYTEORDER == SDL_BIG_ENDIAN |
119 |
|
|
int32_t swap = SDL_Swap64(value); |
120 |
|
|
memcpy(mData + CAST_SIZE(mPos), &swap, sizeof(int64_t)); |
121 |
|
|
#else // SDL_BYTEORDER == SDL_BIG_ENDIAN |
122 |
|
|
|
123 |
|
|
memcpy(mData + CAST_SIZE(mPos), &value, sizeof(int64_t)); |
124 |
|
|
#endif // SDL_BYTEORDER == SDL_BIG_ENDIAN |
125 |
|
|
|
126 |
|
|
mPos += 8; |
127 |
|
|
} |
128 |
|
|
|
129 |
|
|
void MessageOut::writeBeingId(const BeingId value, const char *const str) |
130 |
|
|
{ |
131 |
|
|
writeInt32(toInt(value, int32_t), str); |
132 |
|
|
} |
133 |
|
|
|
134 |
|
|
void MessageOut::writeFloat(const float value, const char *const str) |
135 |
|
|
{ |
136 |
|
|
#ifdef ENABLEDEBUGLOG |
137 |
|
|
std::string text = strprintf("writeFloat: %f", value); |
138 |
|
|
DEBUGLOG2(text, mPos, str); |
139 |
|
|
#endif |
140 |
|
|
expand(4); |
141 |
|
|
memcpy(mData + CAST_SIZE(mPos), &value, sizeof(float)); |
142 |
|
|
mPos += 4; |
143 |
|
|
} |
144 |
|
|
|
145 |
|
|
#define LOBYTE(w) (CAST_U8(w)) |
146 |
|
|
#define HIBYTE(w) (CAST_U8((CAST_U16(w)) >> 8)) |
147 |
|
|
|
148 |
|
|
void MessageOut::writeCoordinates(const uint16_t x, |
149 |
|
|
const uint16_t y, |
150 |
|
|
unsigned char direction, |
151 |
|
|
const char *const str) |
152 |
|
|
{ |
153 |
|
|
DEBUGLOG2(strprintf("writeCoordinates: %u,%u %u", |
154 |
|
|
CAST_U32(x), |
155 |
|
|
CAST_U32(y), |
156 |
|
|
CAST_U32(direction)), mPos, str); |
157 |
|
|
unsigned char *const data = reinterpret_cast<unsigned char*>(mData) |
158 |
|
|
+ CAST_SIZE(mPos); |
159 |
|
|
expand(3); |
160 |
|
|
mPos += 3; |
161 |
|
|
|
162 |
|
|
uint16_t temp = x; |
163 |
|
|
temp <<= 6; |
164 |
|
|
data[0] = 0; |
165 |
|
|
data[1] = 1; |
166 |
|
|
data[2] = 2; |
167 |
|
|
data[0] = HIBYTE(temp); |
168 |
|
|
data[1] = CAST_U8(temp); |
169 |
|
|
temp = y; |
170 |
|
|
temp <<= 4; |
171 |
|
|
data[1] |= HIBYTE(temp); |
172 |
|
|
data[2] = LOBYTE(temp); |
173 |
|
|
direction = toServerDirection(direction); |
174 |
|
|
data[2] |= direction; |
175 |
|
|
} |
176 |
|
|
|
177 |
|
|
void MessageOut::writeString(const std::string &string, |
178 |
|
|
int length, |
179 |
|
|
const char *const str) |
180 |
|
|
{ |
181 |
|
|
int stringLength = CAST_S32(string.length()); |
182 |
|
|
if (length < 0) |
183 |
|
|
{ |
184 |
|
|
// Write the length at the start if not fixed |
185 |
|
|
writeInt16(CAST_S16(stringLength), "len"); |
186 |
|
|
length = stringLength; |
187 |
|
|
} |
188 |
|
|
else if (length < stringLength) |
189 |
|
|
{ |
190 |
|
|
// Make sure the length of the string is no longer than specified |
191 |
|
|
stringLength = length; |
192 |
|
|
} |
193 |
|
|
expand(length); |
194 |
|
|
|
195 |
|
|
// Write the actual string |
196 |
|
|
memcpy(mData + CAST_SIZE(mPos), string.c_str(), stringLength); |
197 |
|
|
|
198 |
|
|
// Pad remaining space with zeros |
199 |
|
|
if (length > stringLength) |
200 |
|
|
{ |
201 |
|
|
memset(mData + CAST_SIZE(mPos + stringLength), |
202 |
|
|
'\0', |
203 |
|
|
length - stringLength); |
204 |
|
|
} |
205 |
|
|
|
206 |
|
|
DEBUGLOG2("writeString: " + string, mPos, str); |
207 |
|
|
mPos += length; |
208 |
|
|
} |
209 |
|
|
|
210 |
|
|
void MessageOut::writeStringNoLog(const std::string &string, |
211 |
|
|
int length, |
212 |
|
|
const char *const str) |
213 |
|
|
{ |
214 |
|
|
int stringLength = CAST_S32(string.length()); |
215 |
|
|
if (length < 0) |
216 |
|
|
{ |
217 |
|
|
// Write the length at the start if not fixed |
218 |
|
|
writeInt16(CAST_S16(stringLength), "len"); |
219 |
|
|
length = stringLength; |
220 |
|
|
} |
221 |
|
|
else if (length < stringLength) |
222 |
|
|
{ |
223 |
|
|
// Make sure the length of the string is no longer than specified |
224 |
|
|
stringLength = length; |
225 |
|
|
} |
226 |
|
|
expand(length); |
227 |
|
|
|
228 |
|
|
// Write the actual string |
229 |
|
|
memcpy(mData + CAST_SIZE(mPos), string.c_str(), stringLength); |
230 |
|
|
|
231 |
|
|
// Pad remaining space with zeros |
232 |
|
|
if (length > stringLength) |
233 |
|
|
{ |
234 |
|
|
memset(mData + CAST_SIZE(mPos + stringLength), |
235 |
|
|
'\0', |
236 |
|
|
length - stringLength); |
237 |
|
|
} |
238 |
|
|
|
239 |
|
|
DEBUGLOG2("writeString: ***", mPos, str); |
240 |
|
|
mPos += length; |
241 |
|
|
} |
242 |
|
|
|
243 |
|
|
const char *MessageOut::getData() const |
244 |
|
|
{ |
245 |
|
|
return mData; |
246 |
|
|
} |
247 |
|
|
|
248 |
|
|
unsigned int MessageOut::getDataSize() const |
249 |
|
|
{ |
250 |
|
|
return mDataSize; |
251 |
|
|
} |
252 |
|
|
|
253 |
|
|
unsigned char MessageOut::toServerDirection(unsigned char direction) |
254 |
|
|
{ |
255 |
|
|
// Translate direction to eAthena format |
256 |
|
|
switch (direction) |
257 |
|
|
{ |
258 |
|
|
case 1: // DOWN |
259 |
|
|
direction = 0; |
260 |
|
|
break; |
261 |
|
|
case 3: // DOWN | LEFT |
262 |
|
|
direction = 1; |
263 |
|
|
break; |
264 |
|
|
case 2: // LEFT |
265 |
|
|
direction = 2; |
266 |
|
|
break; |
267 |
|
|
case 6: // LEFT | UP |
268 |
|
|
direction = 3; |
269 |
|
|
break; |
270 |
|
|
case 4: // UP |
271 |
|
|
direction = 4; |
272 |
|
|
break; |
273 |
|
|
case 12: // UP | RIGHT |
274 |
|
|
direction = 5; |
275 |
|
|
break; |
276 |
|
|
case 8: // RIGHT |
277 |
|
|
direction = 6; |
278 |
|
|
break; |
279 |
|
|
case 9: // RIGHT + DOWN |
280 |
|
|
direction = 7; |
281 |
|
|
break; |
282 |
|
|
default: |
283 |
|
|
// OOPSIE! Impossible or unknown |
284 |
|
|
direction = CAST_U8(-1); |
285 |
|
|
break; |
286 |
|
|
} |
287 |
|
|
return direction; |
288 |
|
|
} |
289 |
|
|
|
290 |
|
|
} // namespace Net |