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
MessageOut(const int16_t id)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
writeInt8(const int8_t value,const char * const str)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
writeInt16(const int16_t value,const char * const str)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
writeInt32(const int32_t value,const char * const str)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
writeItemId(const int32_t value,const char * const str)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
writeInt64(const int64_t value,const char * const str)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
writeBeingId(const BeingId value,const char * const str)129 void MessageOut::writeBeingId(const BeingId value, const char *const str)
130 {
131 writeInt32(toInt(value, int32_t), str);
132 }
133
writeFloat(const float value,const char * const str)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
writeCoordinates(const uint16_t x,const uint16_t y,unsigned char direction,const char * const str)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
writeString(const std::string & string,int length,const char * const str)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
writeStringNoLog(const std::string & string,int length,const char * const str)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
getData() const243 const char *MessageOut::getData() const
244 {
245 return mData;
246 }
247
getDataSize() const248 unsigned int MessageOut::getDataSize() const
249 {
250 return mDataSize;
251 }
252
toServerDirection(unsigned char direction)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
291