GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/tmwa/charserverrecv.cpp Lines: 1 132 0.8 %
Date: 2021-03-17 Branches: 0 62 0.0 %

Line Branch Exec Source
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/tmwa/charserverrecv.h"
25
26
#include "client.h"
27
#include "configuration.h"
28
#include "settings.h"
29
30
#include "gui/windows/charcreatedialog.h"
31
#include "gui/windows/okdialog.h"
32
33
#include "gui/widgets/createwidget.h"
34
35
#include "net/character.h"
36
#include "net/charserverhandler.h"
37
#include "net/messagein.h"
38
#include "net/serverfeatures.h"
39
40
#include "net/ea/token.h"
41
42
#include "net/tmwa/gamehandler.h"
43
#include "net/tmwa/loginhandler.h"
44
#include "net/tmwa/network.h"
45
#include "net/tmwa/sprite.h"
46
47
#include "resources/iteminfo.h"
48
49
#include "resources/db/itemdb.h"
50
51
#include "utils/dtor.h"
52
#include "utils/gettext.h"
53
54
#include "debug.h"
55
56
namespace TmwAthena
57
{
58
59
extern ServerInfo mapServer;
60
61
extern ServerInfo charServer;
62
63
void CharServerRecv::readPlayerData(Net::MessageIn &msg,
64
                                    Net::Character *const character)
65
{
66
    if (character == nullptr)
67
        return;
68
69
    const Token &token =
70
        static_cast<LoginHandler*>(loginHandler)->getToken();
71
72
    LocalPlayer *const tempPlayer = new LocalPlayer(
73
        msg.readBeingId("account id"), BeingTypeId_zero);
74
75
    PlayerInfoBackend &data = character->data;
76
    data.mAttributes[Attributes::PLAYER_EXP] = msg.readInt32("base exp");
77
    data.mAttributes[Attributes::MONEY] = msg.readInt32("money");
78
    data.mAttributes[Attributes::PLAYER_JOB_EXP] = msg.readInt32("job exp");
79
    data.mAttributes[Attributes::PLAYER_JOB_LEVEL] =
80
        msg.readInt32("job level");
81
82
    const int shoes = msg.readInt16("shoes");
83
    const int gloves = msg.readInt16("gloves");
84
    const int cape = msg.readInt16("cape");
85
    const int misc1 = msg.readInt16("misc1");
86
87
    msg.readInt32("option");
88
    tempPlayer->setKarma(msg.readInt32("karma"));
89
    tempPlayer->setManner(msg.readInt32("manner"));
90
    msg.readInt16("character points left");
91
92
    data.mAttributes[Attributes::PLAYER_HP] = msg.readInt16("hp");
93
    data.mAttributes[Attributes::PLAYER_MAX_HP] = msg.readInt16("max hp");
94
    data.mAttributes[Attributes::PLAYER_MP] = msg.readInt16("mp");
95
    data.mAttributes[Attributes::PLAYER_MAX_MP] = msg.readInt16("max mp");
96
97
    msg.readInt16("speed");
98
    const uint16_t race = msg.readInt16("class");
99
    const uint8_t hairStyle = msg.readUInt8("hair style");
100
    const uint16_t look = msg.readUInt8("look");
101
    tempPlayer->setSubtype(fromInt(race, BeingTypeId), look);
102
    const uint16_t weapon = msg.readInt16("weapon");
103
    tempPlayer->setSpriteId(SPRITE_BODY,
104
        weapon);
105
    tempPlayer->setWeaponId(weapon);
106
107
    data.mAttributes[Attributes::PLAYER_BASE_LEVEL] = msg.readInt16("level");
108
109
    msg.readInt16("skill point");
110
    const int bottomClothes = msg.readInt16("bottom clothes");
111
    const int shield = msg.readInt16("shield");
112
113
    const int hat = msg.readInt16("hat");
114
    const int topClothes = msg.readInt16("top clothes");
115
116
    const ItemColor hairColor = fromInt(
117
        msg.readUInt8("hair color"), ItemColor);
118
    msg.readUInt8("unused");
119
    if (hairStyle == 0)
120
    {
121
        tempPlayer->unSetSprite(SPRITE_HAIR_COLOR);
122
    }
123
    else
124
    {
125
        tempPlayer->setSpriteColor(SPRITE_HAIR_COLOR,
126
            hairStyle * -1,
127
            ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
128
    }
129
    tempPlayer->setHairColor(hairColor);
130
131
    const int misc2 = msg.readInt16("misc2");
132
    tempPlayer->setName(msg.readString(24, "name"));
133
134
    character->dummy = tempPlayer;
135
136
    character->data.mStats[Attributes::PLAYER_STR].base = msg.readUInt8("str");
137
    character->data.mStats[Attributes::PLAYER_AGI].base = msg.readUInt8("agi");
138
    character->data.mStats[Attributes::PLAYER_VIT].base = msg.readUInt8("vit");
139
    character->data.mStats[Attributes::PLAYER_INT].base = msg.readUInt8("int");
140
    character->data.mStats[Attributes::PLAYER_DEX].base = msg.readUInt8("dex");
141
    character->data.mStats[Attributes::PLAYER_LUK].base = msg.readUInt8("luk");
142
143
    tempPlayer->setSpriteId(SPRITE_HAIR,
144
        shoes);
145
    tempPlayer->setSpriteId(SPRITE_SHOES,
146
        gloves);
147
    tempPlayer->setSpriteId(SPRITE_SHIELD,
148
        cape);
149
    tempPlayer->setSpriteId(SPRITE_HEAD_TOP,
150
        misc1);
151
    tempPlayer->setSpriteId(SPRITE_WEAPON,
152
        bottomClothes);
153
    tempPlayer->setSpriteId(SPRITE_FLOOR,
154
        shield);
155
    tempPlayer->setSpriteId(SPRITE_CLOTHES_COLOR,
156
        hat);
157
    tempPlayer->setSpriteId(SPRITE_HEAD_BOTTOM,
158
        topClothes);
159
    tempPlayer->setSpriteId(SPRITE_HEAD_MID,
160
        misc2);
161
162
    character->slot = msg.readUInt8("slot");
163
    const uint8_t sex = CAST_U8(msg.readUInt8("gender"));
164
    if (serverFeatures->haveCreateCharGender())
165
        tempPlayer->setGender(Being::intToGender(sex));
166
    else
167
        tempPlayer->setGender(token.sex);
168
}
169
170
void CharServerRecv::processCharLogin(Net::MessageIn &msg)
171
{
172
    BLOCK_START("CharServerRecv::processCharLogin")
173
174
    msg.readInt16("len");
175
    const int slots = msg.readInt16("slots");
176
    if (slots > 0 && slots < 30)
177
        loginData.characterSlots = CAST_U16(slots);
178
179
    msg.skip(18, "unused");
180
181
    delete_all(Net::CharServerHandler::mCharacters);
182
    Net::CharServerHandler::mCharacters.clear();
183
184
    // Derive number of characters from message length
185
    const int count = (msg.getLength() - 24) / 106;
186
187
    for (int i = 0; i < count; ++i)
188
    {
189
        Net::Character *const character = new Net::Character;
190
        readPlayerData(msg, character);
191
        Net::CharServerHandler::mCharacters.push_back(character);
192
        if (character->dummy != nullptr)
193
        {
194
            logger->log("CharServer: Player: %s (%d)",
195
                character->dummy->getName().c_str(), character->slot);
196
        }
197
    }
198
199
    client->setState(State::CHAR_SELECT);
200
    BLOCK_END("CharServerRecv::processCharLogin")
201
}
202
203
void CharServerRecv::processCharMapInfo(Net::MessageIn &restrict msg)
204
{
205
    Network *const network = Network::mInstance;
206
    ServerInfo &server = mapServer;
207
    BLOCK_START("CharServerRecv::processCharMapInfo")
208
    PlayerInfo::setCharId(msg.readInt32("char id?"));
209
    GameHandler::setMap(msg.readString(16, "map name"));
210
    if (config.getBoolValue("usePersistentIP") || settings.persistentIp)
211
    {
212
        msg.readInt32("ip address");
213
        server.hostname = settings.serverName;
214
    }
215
    else
216
    {
217
        server.hostname = ipToString(msg.readInt32("ip address"));
218
    }
219
    server.port = msg.readInt16("port");
220
    server.althostname = charServer.althostname;
221
222
    // Prevent the selected local player from being deleted
223
    localPlayer = Net::CharServerHandler::mSelectedCharacter->dummy;
224
    PlayerInfo::setBackend(Net::CharServerHandler::mSelectedCharacter->data);
225
226
    Net::CharServerHandler::mSelectedCharacter->dummy = nullptr;
227
228
    charServerHandler->clear();
229
    Net::CharServerHandler::updateCharSelectDialog();
230
231
    if (network != nullptr)
232
        network->disconnect();
233
    client->setState(State::CONNECT_GAME);
234
    BLOCK_END("CharServerRecv::processCharMapInfo")
235
}
236
237
void CharServerRecv::processChangeMapServer(Net::MessageIn &msg)
238
{
239
    Network *const network = Network::mInstance;
240
    ServerInfo &server = mapServer;
241
    BLOCK_START("CharServerRecv::processChangeMapServer")
242
    if (network == nullptr)
243
    {
244
        BLOCK_END("CharServerRecv::processChangeMapServer")
245
        return;
246
    }
247
    GameHandler::setMap(msg.readString(16, "map name"));
248
    const int x = msg.readInt16("x");
249
    const int y = msg.readInt16("y");
250
    if (config.getBoolValue("usePersistentIP") || settings.persistentIp)
251
    {
252
        msg.readInt32("ip address");
253
        server.hostname = settings.serverName;
254
    }
255
    else
256
    {
257
        server.hostname = ipToString(msg.readInt32("ip address"));
258
    }
259
    server.port = msg.readInt16("port");
260
261
    network->disconnect();
262
    client->setState(State::CHANGE_MAP);
263
    if (localPlayer != nullptr)
264
    {
265
        localPlayer->setTileCoords(x, y);
266
        localPlayer->setMap(nullptr);
267
    }
268
    BLOCK_END("CharServerRecv::processChangeMapServer")
269
}
270
271
void CharServerRecv::processCharCreate(Net::MessageIn &msg)
272
{
273
    BLOCK_START("CharServerRecv::processCharCreate")
274
    Net::Character *const character = new Net::Character;
275
    readPlayerData(msg, character);
276
    Net::CharServerHandler::mCharacters.push_back(character);
277
278
    Net::CharServerHandler::updateCharSelectDialog();
279
280
    // Close the character create dialog
281
    Net::CharServerHandler::mCharCreateDialog->scheduleDelete();
282
    Net::CharServerHandler::mCharCreateDialog = nullptr;
283
    BLOCK_END("CharServerRecv::processCharCreate")
284
}
285
286
void CharServerRecv::processCharDeleteFailed(Net::MessageIn &msg)
287
{
288
    BLOCK_START("CharServerRecv::processCharDeleteFailed")
289
    Net::CharServerHandler::unlockCharSelectDialog();
290
    msg.readUInt8("error");
291
    CREATEWIDGET(OkDialog,
292
        // TRANSLATORS: error header
293
        _("Error"),
294
        // TRANSLATORS: error message
295
        _("Failed to delete character."),
296
        // TRANSLATORS: ok dialog button
297
        _("OK"),
298
        DialogType::ERROR,
299
        Modal_true,
300
        ShowCenter_true,
301
        nullptr,
302
        260);
303
    BLOCK_END("CharServerRecv::processCharDeleteFailed")
304
}
305
306
2
}  // namespace TmwAthena