1 // SuperTuxKart - a fun racing game with go-kart
2 // Copyright (C) 2013-2015 Glenn De Jonghe
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 3
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 #include "network/server.hpp"
19 #include "config/player_manager.hpp"
20 #include "io/xml_node.hpp"
21 #include "online/online_player_profile.hpp"
22 #include "online/online_profile.hpp"
23 #include "online/profile_manager.hpp"
24 #include "network/network_config.hpp"
25 #include "network/socket_address.hpp"
26 #include "states_screens/online/online_screen.hpp"
27 #include "tracks/track_manager.hpp"
28 #include "utils/constants.hpp"
29 #include "utils/string_utils.hpp"
30
31 #include <algorithm>
32
33 /** Constructor based on XML data received from the stk server.
34 * \param xml The data for one server as received as part of the
35 * get-all stk-server request.
36 */
Server(const XMLNode & server_info)37 Server::Server(const XMLNode& server_info) : m_supports_encrytion(true)
38 {
39 const XMLNode& xml = *server_info.getNode("server-info");
40 m_address.reset(new SocketAddress());
41
42 m_reconnect_when_quit_lobby = false;
43 m_ipv6_connection = false;
44 m_name = "";
45 m_server_id = 0;
46 m_current_players = 0;
47 m_max_players = 0;
48 m_distance = 0.0f;
49 m_server_mode = 0;
50 xml.get("game_mode", &m_server_mode);
51 unsigned server_data = 0;
52 xml.get("difficulty", &server_data);
53 m_difficulty = (RaceManager::Difficulty)server_data;
54
55 xml.get("name", &m_lower_case_name);
56 m_name = StringUtils::xmlDecode(m_lower_case_name);
57 m_lower_case_name = StringUtils::toLowerCase(
58 StringUtils::wideToUtf8(m_name));
59
60 xml.get("id", &m_server_id);
61 xml.get("host_id", &m_server_owner);
62 xml.get("max_players", &m_max_players);
63 xml.get("current_players", &m_current_players);
64 xml.get("current_track", &m_current_track);
65 uint32_t ip;
66 xml.get("ip", &ip);
67 m_address->setIP(ip);
68 uint16_t port;
69 xml.get("port", &port);
70 m_address->setPort(port);
71 std::string ipv6_address;
72 xml.get("ipv6", &ipv6_address);
73 if (!ipv6_address.empty())
74 m_ipv6_address.reset(new SocketAddress(ipv6_address, port));
75 xml.get("private_port", &m_private_port);
76 xml.get("password", &m_password_protected);
77 xml.get("game_started", &m_game_started);
78 xml.get("distance", &m_distance);
79 xml.get("country_code", &m_country_code);
80 m_server_owner_name = L"-";
81 m_server_owner_lower_case_name = "-";
82
83 const XMLNode* players = server_info.getNode("players");
84 assert(players);
85 for (unsigned int i = 0; i < players->getNumNodes(); i++)
86 {
87 const XMLNode* player_info = players->getNode(i);
88 assert(player_info->getName() == "player-info");
89 std::string username;
90 std::tuple<int, core::stringw, double, float> t;
91 // Default rank and scores if none
92 std::get<0>(t) = -1;
93 std::get<2>(t) = 2000.0;
94 player_info->get("rank", &std::get<0>(t));
95 player_info->get("username", &username);
96 std::get<1>(t) = StringUtils::utf8ToWide(username);
97 std::string country;
98 player_info->get("country-code", &country);
99 const core::stringw& flag = StringUtils::getCountryFlag(country);
100 if (!flag.empty())
101 {
102 std::get<1>(t) += L" ";
103 std::get<1>(t) += flag;
104 }
105 m_lower_case_player_names += StringUtils::toLowerCase(username);
106 player_info->get("scores", &std::get<2>(t));
107 float time_played = 0.0f;
108 player_info->get("time-played", &time_played);
109 std::get<3>(t) = time_played;
110 m_players.push_back(t);
111 }
112 // Sort by rank
113 std::sort(m_players.begin(), m_players.end(),
114 [](const std::tuple<int, core::stringw, double, float>& a,
115 const std::tuple<int, core::stringw, double, float>& b)->bool
116 {
117 return std::get<0>(a) < std::get<0>(b);
118 });
119
120 // Show owner name as Official right now if official server hoster account
121 m_official = false;
122 xml.get("official", &m_official);
123 if (m_official)
124 {
125 m_server_owner_name = L"\u2606\u2605STK\u2605\u2606";
126 m_server_owner_lower_case_name = "stk";
127 return;
128 }
129
130 // Display server owner name if they're your friend or localhost
131 Online::OnlineProfile* opp =
132 PlayerManager::getCurrentPlayer()->getProfile();
133 // Check localhost owner
134 if (opp && opp->getID() == m_server_owner)
135 {
136 m_server_owner_name = opp->getUserName();
137 m_server_owner_lower_case_name = StringUtils::toLowerCase
138 (StringUtils::wideToUtf8(m_server_owner_name));
139 }
140 else if (opp && opp->hasFetchedFriends())
141 {
142 // Check friend(s)
143 for (uint32_t user_id : opp->getFriends())
144 {
145 if (user_id == m_server_owner)
146 {
147 Online::OnlineProfile* friend_profile =
148 Online::ProfileManager::get()->getProfileByID(user_id);
149 if (friend_profile)
150 {
151 m_server_owner_name = friend_profile->getUserName();
152 m_server_owner_lower_case_name = StringUtils::toLowerCase
153 (StringUtils::wideToUtf8(m_server_owner_name));
154 }
155 }
156 }
157 }
158
159 } // Server(const XML&)
160
161 // ----------------------------------------------------------------------------
162 /** Manual server creation, based on data received from a LAN server discovery
163 * (see ServersManager::getLANRefresh) or local graphics server creation
164 * where the server info is known already.
165 * \param server_id ID of server.
166 * \param name Name of the server.
167 * \param max_players Maximum number of players allowed on this server.
168 * \param current_players The currently connected number of players.
169 * \param difficulty The difficulty of the server.
170 * \param server_mode The game modes of the server (including minor and major).
171 * \param address IP and port of the server.
172 * \param password_protected True if can only be joined with a password.
173 * \param game_started True if a game has already begun in the server.
174 * \param current_track If server is in game, store the track ident
175 */
Server(unsigned server_id,const core::stringw & name,int max_players,int current_players,unsigned difficulty,unsigned server_mode,const SocketAddress & address,bool password_protected,bool game_started,const std::string & current_track)176 Server::Server(unsigned server_id, const core::stringw &name, int max_players,
177 int current_players, unsigned difficulty, unsigned server_mode,
178 const SocketAddress &address, bool password_protected,
179 bool game_started, const std::string& current_track)
180 : m_supports_encrytion(false)
181 {
182 m_reconnect_when_quit_lobby = false;
183 m_ipv6_connection = false;
184 m_name = name;
185 m_lower_case_name = StringUtils::toLowerCase(StringUtils::wideToUtf8(name));
186 m_server_id = server_id;
187 m_server_owner = 0;
188 m_current_players = current_players;
189 m_max_players = max_players;
190 m_address.reset(new SocketAddress(address));
191
192 // In case of LAN server, public and private port are the same.
193 m_private_port = m_address->getPort();
194 m_difficulty = (RaceManager::Difficulty)difficulty;
195 m_server_mode = server_mode;
196 m_password_protected = password_protected;
197 m_distance = 0.0f;
198 m_official = false;
199 m_game_started = game_started;
200 m_current_track = current_track;
201 } // server(server_id, ...)
202
203 // ----------------------------------------------------------------------------
~Server()204 Server::~Server()
205 {
206 } // ~Server
207
208 // ----------------------------------------------------------------------------
getCurrentTrack() const209 Track* Server::getCurrentTrack() const
210 {
211 if (!m_current_track.empty())
212 return track_manager->getTrack(m_current_track);
213 return NULL;
214 } // getCurrentTrack
215
216 // ----------------------------------------------------------------------------
searchByName(const std::string & lower_case_word)217 bool Server::searchByName(const std::string& lower_case_word)
218 {
219 auto list = StringUtils::split(lower_case_word, ' ', false);
220 bool server_name_found = true;
221 for (auto& word : list)
222 {
223 const std::string& for_search = m_lower_case_name +
224 m_lower_case_player_names;
225 server_name_found = server_name_found &&
226 for_search.find(word) != std::string::npos;
227 }
228 return server_name_found;
229 } // searchByName
230
231 // ----------------------------------------------------------------------------
setIPV6Address(const SocketAddress & addr)232 void Server::setIPV6Address(const SocketAddress& addr)
233 {
234 m_ipv6_address.reset(new SocketAddress(addr));
235 } // setIPV6Address
236
237 // ----------------------------------------------------------------------------
setAddress(const SocketAddress & addr)238 void Server::setAddress(const SocketAddress& addr)
239 {
240 m_address.reset(new SocketAddress(addr));
241 } // setAddress
242
243 // ----------------------------------------------------------------------------
saveServer() const244 void UserDefinedServer::saveServer() const
245 {
246 OnlineScreen::getInstance()->setEnteredServerName(m_name);
247 } // saveServer
248