Merge lp:~widelands-dev/widelands/dedicated_out_of_main into lp:widelands

Proposed by SirVer
Status: Merged
Merged at revision: 7798
Proposed branch: lp:~widelands-dev/widelands/dedicated_out_of_main
Merge into: lp:widelands
Diff against target: 3599 lines (+457/-1848)
25 files modified
src/CMakeLists.txt (+0/-3)
src/io/CMakeLists.txt (+0/-13)
src/io/dedicated_log.cc (+0/-342)
src/io/dedicated_log.h (+0/-90)
src/logic/editor_game_base.cc (+1/-5)
src/logic/game.cc (+56/-108)
src/logic/game.h (+13/-7)
src/logic/game_settings.h (+0/-11)
src/main.cc (+0/-57)
src/map_io/map_building_packet.cc (+1/-2)
src/network/CMakeLists.txt (+0/-1)
src/network/internet_gaming.cc (+21/-22)
src/network/netclient.cc (+47/-163)
src/network/netclient.h (+0/-2)
src/network/nethost.cc (+102/-593)
src/network/nethost.h (+1/-8)
src/network/network_protocol.h (+7/-35)
src/sound/sound_handler.h (+0/-1)
src/ui_fsmenu/launch_mpg.cc (+0/-10)
src/ui_fsmenu/loadgame.cc (+164/-179)
src/ui_fsmenu/mapselect.cc (+39/-113)
src/wlapplication.cc (+2/-77)
src/wlapplication.h (+1/-1)
src/wlapplication_messages.cc (+0/-1)
src/wui/chat_msg_layout.cc (+2/-4)
To merge this branch: bzr merge lp:~widelands-dev/widelands/dedicated_out_of_main
Reviewer Review Type Date Requested Status
Tino Approve
GunChleoc Approve
Review via email: mp+285268@code.launchpad.net

Commit message

Remove --dedicated commandline option and associated code.

Rational: --dedicated allowed people who could host a game to keep a server running that people who could not host could control to play games. This is a great feature, but it came at a price: dedicated required a lot of if () else () in many places, i.e. it was very widespread in the code. One of the most pervasive problems was that dedicated could not spin up a Graphic() instance, therfore g_gr == nullptr and a lot of code did not check for that - since g_gr is never null if the game is run normally. Therefore it was easily broken - I am not sure if it worked in b18, but it has not worked for at least a year.
Another problem was that dedicated is essentially a host instance, i.e. it has to run the full game logic for each game that is played. So it is prohibitively expensive to run it (for example) on the server. So we would have needed a donator to even provide another instance that could be used.

We also have a plan of fixing the hosting problem in a principled way: through the proxy server that is spawned by the metaserver that will forward packets between players. Unfortunately, this is not implemented yet and it will not be for b19.

Description of the change

Requires https://code.launchpad.net/~widelands-dev/widelands/different_replay_names/+merge/285265 to be merged first.

Spend an hour today trying to fix --dedicated. Then decided it was too difficult after I could not follow the various state machines anymore and after it kept crashing. Now I ripped it out. This closes a few bugs related to --dedicated and simplifies the code, but of course the dedicated feature is gone for good.

To post a comment you must log in.
Revision history for this message
GunChleoc (gunchleoc) wrote :

Please have a look at my code review commit - there is a NOCOM question in there.

Also pinging Tino, because some WIN32 includes have been removed.

review: Approve
Revision history for this message
SirVer (sirver) wrote :

// NOCOM why was this deleted? if (!complete) throw wexception("Out of memory");

because it is rather pointless. We allocate memory everywhere and never check for OOM errors. One of the reasons is that if the OS does not have any more memory to give you, it will not give you any memory for creating the error message string or the exception. This will kill your process rather quickly anyways.

Tino, if that compiles for you, could you merge?

Revision history for this message
Tino (tino79) wrote :

Compiles, does work fine. No regressionson windows found.

@bunnybot merge

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/CMakeLists.txt'
--- src/CMakeLists.txt 2014-12-06 12:22:35 +0000
+++ src/CMakeLists.txt 2016-02-07 08:11:43 +0000
@@ -106,7 +106,6 @@
106 graphic_text106 graphic_text
107 graphic_text_layout107 graphic_text_layout
108 helper108 helper
109 io_dedicated_log
110 io_filesystem109 io_filesystem
111 logic110 logic
112 logic_game_controller111 logic_game_controller
@@ -130,8 +129,6 @@
130 base_exceptions129 base_exceptions
131)130)
132131
133
134
135if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD" OR CMAKE_SYSTEM_NAME MATCHES "OpenBSD")132if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD" OR CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
136 target_link_libraries(widelands_ball_of_mud ${EXECINFO_LIBRARY})133 target_link_libraries(widelands_ball_of_mud ${EXECINFO_LIBRARY})
137endif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD" OR CMAKE_SYSTEM_NAME MATCHES "OpenBSD")134endif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD" OR CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
138135
=== modified file 'src/io/CMakeLists.txt'
--- src/io/CMakeLists.txt 2014-11-28 16:40:55 +0000
+++ src/io/CMakeLists.txt 2016-02-07 08:11:43 +0000
@@ -44,16 +44,3 @@
44 io_stream44 io_stream
45 third_party_minizip45 third_party_minizip
46)46)
47
48
49wl_library(io_dedicated_log
50 SRCS
51 dedicated_log.h
52 dedicated_log.cc
53 DEPENDS
54 base_i18n
55 base_log
56 chat
57 io_fileread
58 io_filesystem
59)
6047
=== removed file 'src/io/dedicated_log.cc'
--- src/io/dedicated_log.cc 2014-09-30 05:41:55 +0000
+++ src/io/dedicated_log.cc 1970-01-01 00:00:00 +0000
@@ -1,342 +0,0 @@
1/*
2 * Copyright (C) 2012-2013 by the Widelands Development Team
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 2
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#include "io/dedicated_log.h"
21
22#include <string>
23
24#include <boost/format.hpp>
25
26#include "base/i18n.h"
27#include "base/log.h"
28#include "io/filesystem/layered_filesystem.h"
29
30/// The dedicated server logger
31static DedicatedLog * logger;
32
33extern std::ostream & wout;
34
35void dedicatedlog(const char * const fmt, ...) {
36 char buffer[2048];
37 va_list va;
38
39 va_start(va, fmt);
40 vsnprintf(buffer, sizeof(buffer), fmt, va);
41 va_end(va);
42
43 // Here comes the difference to widelands standard log() ;)
44 DedicatedLog::get()->dlog(buffer);
45
46 wout << buffer;
47 wout.flush();
48}
49
50/// protected constructor
51DedicatedLog::DedicatedLog()
52:
53m_chat_file_path(""),
54m_info_file_path(""),
55m_log_file_path(""),
56d_name(""),
57d_motd(""),
58d_start(""),
59d_logins(0),
60d_logouts(0),
61d_chatmessages(0),
62root(new RealFSImpl("/"))
63{
64 char ts[42];
65 time_t currenttime = time(nullptr);
66 strftime(ts, sizeof(ts), "%a %Y/%m/%d, %H:%M:%S", localtime(&currenttime));
67 d_start = ts;
68 d_ip = (boost::format("\\<%s\\>") % _("unknown")).str();
69}
70
71
72/// \returns the dedicated server logger, if it is not yet initialized, this is done before.
73DedicatedLog * DedicatedLog::get() {
74 if (logger == nullptr)
75 logger = new DedicatedLog();
76 return logger;
77}
78
79
80/**
81 * chat(ChatMessage & c)
82 *
83 * Writes the ChatMessage \arg c to the chat log, if initialized.
84 */
85void DedicatedLog::chat(ChatMessage & c) {
86 if (!m_info_file_path.empty()) {
87 ++d_chatmessages;
88 info_update();
89 }
90
91 if (m_chat_file_path.empty())
92 return;
93
94 std::string temp("<tr>");
95 temp += "<td class=\"time\">";
96 char ts[32];
97 strftime(ts, sizeof(ts), "[%Y-%m-%d, %H:%M]", localtime(&c.time));
98 temp += (boost::format("%s</td><td class=\"player%i\">") % ts % c.playern).str();
99 temp += c.sender.empty() ? "SYSTEM" : c.sender;
100 temp += "</td><td class=\"recipient\"> ->" + c.recipient + "</td><td class=\"message\">";
101 temp += c.msg + "</td></tr>\n";
102 m_chat.print_f("%s", temp.c_str());
103 m_chat.write_append(*root, m_chat_file_path.c_str());
104}
105
106/// Add's a spacer to the chat log
107void DedicatedLog::chat_add_spacer() {
108 if (m_chat_file_path.empty())
109 return;
110
111 m_chat.print_f("<tr><td class=\"space\"></td><td class=\"space\"></td>");
112 m_chat.print_f("<td class=\"space\"></td><td class=\"space\"></td></tr>\n");
113 m_chat.write_append(*root, m_chat_file_path.c_str());
114}
115
116
117/// Sets the basic server informations
118void DedicatedLog::set_server_data(std::string name, std::string motd) {
119 if (!d_name.empty())
120 return;
121 d_name = name;
122 d_motd = motd;
123 info_update();
124}
125
126
127/// Sets the servers ip informations
128void DedicatedLog::set_server_ip(std::string ip) {
129 if (d_ip != ip) {
130 d_ip = ip;
131 info_update();
132 }
133}
134
135
136/// Saves the data of a newly started game
137void DedicatedLog::game_start(std::vector<std::string> clients, std::string mapname) {
138 GameStatistic * new_game = new GameStatistic;
139 new_game->mapname = mapname;
140 new_game->times.push_back(time(nullptr));
141 new_game->clients = clients;
142 d_games.push_back(*new_game);
143 delete new_game;
144 new_game = nullptr;
145 info_update();
146}
147
148
149/// Saves the winners of the last started game
150void DedicatedLog::game_end(std::vector<std::string> winners) {
151 assert(!d_games.empty());
152 d_games.back().winners = winners;
153 d_games.back().times.push_back(time(nullptr));
154 info_update();
155}
156
157
158/// Updates the server information file with current data
159void DedicatedLog::info_update() {
160 if (m_info_file_path.empty())
161 return;
162
163 std::string temp("<table class=\"infohead\">\n");
164 // Basic information
165 temp += "<tr><td class=\"infoname\">Servername</td><td class=\"info\">" + d_name + "</td></tr>\n";
166 temp += "<tr><td class=\"infoname\">Server IP</td><td class=\"info\">" + d_ip + "</td></tr>\n";
167 temp += "<tr><td class=\"infoname\">Server MOTD</td><td class=\"info\">" + d_motd + "</td></tr>\n";
168 temp += "<tr><td class=\"infoname\">Started on</td><td class=\"info\">" + d_start + "</td></tr>\n";
169 temp += "<tr><td class=\"infoname\">Logins</td><td class=\"info\">";
170 temp += std::to_string(d_logins) + "</td></tr>\n";
171 temp += "<tr><td class=\"infoname\">Logouts</td><td class=\"info\">";
172 temp += std::to_string(d_logouts) + "</td></tr>\n";
173 temp += "<tr><td class=\"infoname\">Chat messages</td><td class=\"info\">";
174 temp += std::to_string(d_chatmessages) + "</td></tr>\n";
175 temp += "<tr><td class=\"infoname\">Games started</td><td class=\"info\">";
176 temp += std::to_string(d_games.size()) + "</td></tr>\n";
177 if (!d_games.empty()) {
178 // Games information
179 temp += "</table><br><table class=\"infogames\">\n";
180 temp += "<tr><th>start/end of game</th><th>map name</th><th>client(s)</th><th>winner(s)</th></tr>\n";
181
182 for (uint16_t i = 0; i < d_games.size(); ++i) {
183 assert(!d_games.at(i).clients.empty() && !d_games.at(i).times.empty());
184 // Start and (if already ended) end time
185 char ts[42];
186 strftime(ts, sizeof(ts), "S: %Y/%m/%d, %H:%M:%S", localtime(&d_games.at(i).times.at(0)));
187 temp += (boost::format("<tr><td>%s") % ts).str();
188 if (d_games.at(i).times.size() > 1) {
189 strftime(ts, sizeof(ts), "E: %Y/%m/%d, %H:%M:%S", localtime(&d_games.at(i).times.at(1)));
190 temp += (boost::format("<br>%s") % ts).str();
191 }
192 // Map name
193 temp += (boost::format("</td><td>%s</td><td>") % d_games.at(i).mapname).str();
194 // Players
195 for (uint16_t j = 0; j < d_games.at(i).clients.size(); ++j) {
196 if (j > 0)
197 temp += ", ";
198 temp += d_games.at(i).clients.at(j);
199 }
200 temp += "</td><td>";
201 // Winners
202 for (uint16_t j = 0; j < d_games.at(i).winners.size(); ++j) {
203 if (j > 0)
204 temp += ", ";
205 temp += d_games.at(i).winners.at(j);
206 }
207 temp += "</td></tr>\n";
208 }
209 }
210 temp += "</table>\n";
211 m_chat.print_f("%s", temp.c_str());
212 m_chat.write(*root, m_info_file_path.c_str());
213}
214
215/// Appends the String \arg msg to the log file
216void DedicatedLog::dlog(std::string msg) {
217 if (m_log_file_path.empty())
218 return;
219
220 std::string temp("<tr><td class=\"time\">");
221 char ts[32];
222 time_t * t = new time_t(time(nullptr));
223 strftime(ts, sizeof(ts), "[%Y-%m-%d, %H:%M]", localtime(t));
224 delete t;
225 temp += ts;
226 temp += "</td><td class=\"log\">";
227 temp += msg;
228 temp += "</td></tr>\n";
229 m_chat.print_f("%s", temp.c_str());
230 m_chat.write_append(*root, m_log_file_path.c_str());
231}
232
233
234/**
235 * set_chat_file_path(std::string path)
236 *
237 * Post initialization - this function can be called more than once, but will only handle the input data
238 * as long as the chat file path is not yet set up correctly.
239 * The function takes care:
240 * - Whether the file at \arg path is writeable - \returns false if not.
241 * - About file cleanup - all following data will be attached, therefore the original file will be removed
242 * - About the initial formating like table headers, etc.
243 *
244 * \returns false, if path is not writeable, in all other cases true
245 */
246bool DedicatedLog::set_chat_file_path(std::string path) {
247 if (!m_chat_file_path.empty() || path.empty())
248 return true;
249
250 if (!check_file_writeable(path))
251 return false;
252
253 // Everything's fine, set the path
254 m_chat_file_path = path;
255
256 // Initialize the chat file
257 m_chat.print_f("<tr><th>Time</th><th>Sender</th><th>Recipient</th><th>Message</th></tr>");
258 m_chat.write(*root, m_chat_file_path.c_str()); // Not write_append, to make sure the file is cleared
259 return true;
260}
261
262
263/**
264 * set_info_file_path(std::string path)
265 *
266 * Post initialization - this function can be called more than once, but will only handle the input data
267 * as long as the info file path is not yet set up correctly.
268 * The function takes care:
269 * - Whether the file at \arg path is writeable - \returns false if not.
270 * - About file cleanup - all following data will be attached, therefore the original file will be removed
271 * - About the initial formating like table headers, etc.
272 *
273 * \returns false, if path is not writeable, in all other cases true
274 */
275bool DedicatedLog::set_info_file_path(std::string path) {
276 if (!m_info_file_path.empty() || path.empty())
277 return true;
278
279 if (!check_file_writeable(path))
280 return false;
281
282 // Everything's fine, set the path and write info for the first time;
283 m_info_file_path = path;
284 info_update();
285 return true;
286}
287
288
289/**
290 * set_log_file_path(std::string path)
291 *
292 * Post initialization - this function can be called more than once, but will only handle the input data
293 * as long as the log file path is not yet set up correctly.
294 * The function takes care:
295 * - Whether the file at \arg path is writeable - \returns false if not.
296 * - About file cleanup - all following data will be attached, therefore the original file will be removed
297 * - About the initial formating like table headers, etc.
298 *
299 * \returns false, if path is not writeable, in all other cases true
300 */
301bool DedicatedLog::set_log_file_path (std::string path) {
302 if (!m_log_file_path.empty() || path.empty())
303 return true;
304
305 if (!check_file_writeable(path))
306 return false;
307
308 // Everything's fine, set the path
309 m_log_file_path = path;
310
311 // Initialize the log file
312 m_chat.print_f("<tr><th></th><th>Widelands dedicated server log:</th></tr>\n");
313 m_chat.write(*root, m_log_file_path.c_str()); // Not write_append, to make sure the file is cleared
314 return true;
315}
316
317
318/**
319 * check_file_writeable(std::string & path)
320 *
321 * Checks if a file is writeable to \arg path and if yes and a file of that name is already existing
322 * moves the original file to path + "~".
323 *
324 * \returns false, if path is not writeable or if path is a directory or if the directory the file should be
325 * written to does not exist, in all other cases true.
326 */
327bool DedicatedLog::check_file_writeable(std::string & path) {
328 bool existing = root->file_exists(path);
329 if (existing && root->is_directory(path))
330 return false;
331 if (root->file_is_writeable(path)) {
332 if (existing) {
333 std::string rnpath(path + '~');
334 if (root->file_is_writeable(rnpath))
335 root->fs_rename(path, rnpath);
336 else
337 log("Note: original file %s could not be backuped\n", path.c_str());
338 }
339 return true;
340 }
341 return false;
342}
3430
=== removed file 'src/io/dedicated_log.h'
--- src/io/dedicated_log.h 2014-09-20 09:37:47 +0000
+++ src/io/dedicated_log.h 1970-01-01 00:00:00 +0000
@@ -1,90 +0,0 @@
1/*
2 * Copyright (C) 2012 by the Widelands Development Team
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 2
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#ifndef WL_IO_DEDICATED_LOG_H
21#define WL_IO_DEDICATED_LOG_H
22
23#include "base/log.h"
24#include "chat/chat.h"
25#include "io/filesystem/disk_filesystem.h"
26#include "io/filewrite.h"
27
28void dedicatedlog(const char *, ...) PRINTF_FORMAT(1, 2);
29
30/// This struct writes some statistics and chat data to commandline defined files
31struct DedicatedLog {
32 // Always call DedicatedLog via get() to have only one instance
33 static DedicatedLog * get();
34
35 // chat logging functions
36 void chat_add_spacer();
37 void chat(ChatMessage & c);
38
39 // info logging functions
40 bool write_info_active() {return !m_info_file_path.empty();}
41 void set_server_data(std::string name, std::string motd);
42 void set_server_ip (std::string ip);
43 void client_login() {++d_logins; info_update();} // simple counter
44 void client_logout() {++d_logouts; info_update();} // simple counter
45 void game_start(std::vector<std::string> clients, std::string mapname);
46 void game_end (std::vector<std::string> winners);
47 void info_update(); // updates the info file
48
49 // normal log logging function
50 void dlog(std::string);
51
52 // Post initialization - can be called more than once, but only the first call will be handled
53 // The functions do not only set up the output path, but as well take care about file cleanup and
54 // generate the initial formating
55 bool set_chat_file_path(std::string path);
56 bool set_info_file_path(std::string path);
57 bool set_log_file_path (std::string path);
58
59protected:
60 /// Constructor is protected by purpose - only one instance of DedicatedLog is allowed
61 /// call DedicatedLog::get() instead.
62 DedicatedLog();
63
64private:
65 bool check_file_writeable(std::string & path);
66
67 std::string m_chat_file_path;
68 std::string m_info_file_path;
69 std::string m_log_file_path;
70
71 FileWrite m_chat;
72 FileWrite m_info;
73 FileWrite m_path;
74
75 // statics data
76 struct GameStatistic {
77 std::string mapname;
78 std::vector<std::string> clients;
79 std::vector<std::string> winners;
80 std::vector<time_t> times;
81 };
82 std::string d_name, d_ip, d_motd, d_start;
83 uint32_t d_logins, d_logouts, d_chatmessages;
84 std::vector<GameStatistic> d_games;
85
86
87 RealFSImpl * root;
88};
89
90#endif // end of include guard: WL_IO_DEDICATED_LOG_H
910
=== modified file 'src/logic/editor_game_base.cc'
--- src/logic/editor_game_base.cc 2016-01-28 05:24:34 +0000
+++ src/logic/editor_game_base.cc 2016-02-07 08:11:43 +0000
@@ -83,11 +83,7 @@
83EditorGameBase::~EditorGameBase() {83EditorGameBase::~EditorGameBase() {
84 delete map_;84 delete map_;
85 delete player_manager_.release();85 delete player_manager_.release();
8686 g_sound_handler.egbase_ = nullptr;
87 if (g_gr) { // dedicated does not use the sound_handler
88 assert(this == g_sound_handler.egbase_);
89 g_sound_handler.egbase_ = nullptr;
90 }
91}87}
9288
93void EditorGameBase::think()89void EditorGameBase::think()
9490
=== modified file 'src/logic/game.cc'
--- src/logic/game.cc 2016-02-04 14:00:35 +0000
+++ src/logic/game.cc 2016-02-07 08:11:43 +0000
@@ -24,6 +24,7 @@
24#include <memory>24#include <memory>
25#include <string>25#include <string>
2626
27#include <boost/format.hpp>
27#ifndef _WIN3228#ifndef _WIN32
28#include <SDL.h> // for a dirty hack.29#include <SDL.h> // for a dirty hack.
29#include <unistd.h> // for usleep30#include <unistd.h> // for usleep
@@ -73,10 +74,7 @@
73//#define SYNC_DEBUG74//#define SYNC_DEBUG
7475
75Game::SyncWrapper::~SyncWrapper() {76Game::SyncWrapper::~SyncWrapper() {
76 if (m_dump) {77 if (m_dump != nullptr) {
77 delete m_dump;
78 m_dump = nullptr;
79
80 if (!m_syncstreamsave)78 if (!m_syncstreamsave)
81 g_fs->fs_unlink(m_dumpfname);79 g_fs->fs_unlink(m_dumpfname);
82 }80 }
@@ -84,7 +82,7 @@
8482
85void Game::SyncWrapper::start_dump(const std::string & fname) {83void Game::SyncWrapper::start_dump(const std::string & fname) {
86 m_dumpfname = fname + ".wss";84 m_dumpfname = fname + ".wss";
87 m_dump = g_fs->open_stream_write(m_dumpfname);85 m_dump.reset(g_fs->open_stream_write(m_dumpfname));
88}86}
8987
90static const unsigned long long MINIMUM_DISK_SPACE = 256 * 1024 * 1024;88static const unsigned long long MINIMUM_DISK_SPACE = 256 * 1024 * 1024;
@@ -98,29 +96,21 @@
98 log("\n");96 log("\n");
99#endif97#endif
10098
101 if99 if (m_dump != nullptr && static_cast<int32_t>(m_counter - m_next_diskspacecheck) >= 0) {
102 (m_dump &&
103 static_cast<int32_t>(m_counter - m_next_diskspacecheck) >= 0)
104 {
105 m_next_diskspacecheck = m_counter + 16 * 1024 * 1024;100 m_next_diskspacecheck = m_counter + 16 * 1024 * 1024;
106101
107 if (g_fs->disk_space() < MINIMUM_DISK_SPACE) {102 if (g_fs->disk_space() < MINIMUM_DISK_SPACE) {
108 log("Stop writing to syncstream file: disk is getting full.\n");103 log("Stop writing to syncstream file: disk is getting full.\n");
109 delete m_dump;104 m_dump.reset();
110 m_dump = nullptr;
111 }105 }
112 }106 }
113107
114 if (m_dump) {108 if (m_dump != nullptr) {
115 try {109 try {
116 m_dump->data(sync_data, size);110 m_dump->data(sync_data, size);
117 } catch (const WException &) {111 } catch (const WException &) {
118 log112 log("Writing to syncstream file %s failed. Stop synctream dump.\n", m_dumpfname.c_str());
119 ("Writing to syncstream file %s failed. Stop synctream dump.\n",113 m_dump.reset();
120 m_dumpfname.c_str());
121
122 delete m_dump;
123 m_dump = nullptr;
124 }114 }
125 }115 }
126116
@@ -137,7 +127,6 @@
137 m_writesyncstream (false),127 m_writesyncstream (false),
138 m_state (gs_notrunning),128 m_state (gs_notrunning),
139 m_cmdqueue (*this),129 m_cmdqueue (*this),
140 m_replaywriter (nullptr),
141 /** TRANSLATORS: Win condition for this game has not been set. */130 /** TRANSLATORS: Win condition for this game has not been set. */
142 m_win_condition_displayname(_("Not set"))131 m_win_condition_displayname(_("Not set"))
143{132{
@@ -145,7 +134,6 @@
145134
146Game::~Game()135Game::~Game()
147{136{
148 delete m_replaywriter;
149}137}
150138
151139
@@ -259,7 +247,7 @@
259247
260 set_game_controller(new SinglePlayerGameController(*this, true, 1));248 set_game_controller(new SinglePlayerGameController(*this, true, 1));
261 try {249 try {
262 bool const result = run(&loader_ui, NewSPScenario, script_to_run, false);250 bool const result = run(&loader_ui, NewSPScenario, script_to_run, false, "single_player");
263 delete m_ctrl;251 delete m_ctrl;
264 m_ctrl = nullptr;252 m_ctrl = nullptr;
265 return result;253 return result;
@@ -274,39 +262,34 @@
274/**262/**
275 * Initialize the game based on the given settings.263 * Initialize the game based on the given settings.
276 *264 *
277 * \note loader_ui can be nullptr, if this is run as dedicated server.
278 */265 */
279void Game::init_newgame266void Game::init_newgame
280 (UI::ProgressWindow* loader_ui, const GameSettings& settings)267 (UI::ProgressWindow* loader_ui, const GameSettings& settings)
281{268{
282 if (loader_ui) {269 assert(loader_ui != nullptr);
283 loader_ui->step(_("Preloading map"));270
284 }271 loader_ui->step(_("Preloading map"));
285272
286 assert(!get_map());273 assert(!get_map());
287 set_map(new Map);274 set_map(new Map);
288275
289 std::unique_ptr<MapLoader> maploader276 std::unique_ptr<MapLoader> maploader
290 (map().get_correct_loader(settings.mapfilename));277 (map().get_correct_loader(settings.mapfilename));
278 assert(maploader != nullptr);
291 maploader->preload_map(settings.scenario);279 maploader->preload_map(settings.scenario);
292280
293 if (loader_ui) {281 loader_ui->step(_("Loading world"));
294 loader_ui->step(_("Loading world"));
295 }
296 world();282 world();
297283
298 if (loader_ui) {284 loader_ui->step(_("Loading tribes"));
299 loader_ui->step(_("Loading tribes"));
300 }
301 tribes();285 tribes();
302286
303 std::string const background = map().get_background();287 std::string const background = map().get_background();
304 if (loader_ui) {288 if (!background.empty()) {
305 if (!background.empty()) {289 loader_ui->set_background(background);
306 loader_ui->set_background(background);
307 }
308 loader_ui->step(_("Creating players"));
309 }290 }
291 loader_ui->step(_("Creating players"));
292
310 std::vector<PlayerSettings> shared;293 std::vector<PlayerSettings> shared;
311 std::vector<uint8_t> shared_num;294 std::vector<uint8_t> shared_num;
312 for (uint32_t i = 0; i < settings.players.size(); ++i) {295 for (uint32_t i = 0; i < settings.players.size(); ++i) {
@@ -338,8 +321,7 @@
338 ->add_further_starting_position(shared_num.at(n), shared.at(n).initialization_index);321 ->add_further_starting_position(shared_num.at(n), shared.at(n).initialization_index);
339 }322 }
340323
341 if (loader_ui)324 loader_ui->step(_("Loading map"));
342 loader_ui->step(_("Loading map"));
343 maploader->load_map_complete(*this,325 maploader->load_map_complete(*this,
344 settings.scenario ?326 settings.scenario ?
345 Widelands::MapLoader::LoadType::kScenario :327 Widelands::MapLoader::LoadType::kScenario :
@@ -364,15 +346,13 @@
364 * At return the game is at the same state like a map loaded with Game::init()346 * At return the game is at the same state like a map loaded with Game::init()
365 * Only difference is, that players are already initialized.347 * Only difference is, that players are already initialized.
366 * run<Returncode>() takes care about this difference.348 * run<Returncode>() takes care about this difference.
367 *
368 * \note loader_ui can be nullptr, if this is run as dedicated server.
369 */349 */
370void Game::init_savegame350void Game::init_savegame
371 (UI::ProgressWindow* loader_ui, const GameSettings& settings)351 (UI::ProgressWindow* loader_ui, const GameSettings& settings)
372{352{
373 if (loader_ui) {353 assert(loader_ui != nullptr);
374 loader_ui->step(_("Preloading map"));354
375 }355 loader_ui->step(_("Preloading map"));
376356
377 assert(!get_map());357 assert(!get_map());
378 set_map(new Map);358 set_map(new Map);
@@ -381,11 +361,9 @@
381 Widelands::GamePreloadPacket gpdp;361 Widelands::GamePreloadPacket gpdp;
382 gl.preload_game(gpdp);362 gl.preload_game(gpdp);
383 m_win_condition_displayname = gpdp.get_win_condition();363 m_win_condition_displayname = gpdp.get_win_condition();
384 if (loader_ui) {364 std::string background(gpdp.get_background());
385 std::string background(gpdp.get_background());365 loader_ui->set_background(background);
386 loader_ui->set_background(background);366 loader_ui->step(_("Loading..."));
387 loader_ui->step(_("Loading..."));
388 }
389 gl.load_game(settings.multiplayer);367 gl.load_game(settings.multiplayer);
390 } catch (...) {368 } catch (...) {
391 throw;369 throw;
@@ -427,7 +405,7 @@
427405
428 set_game_controller(new SinglePlayerGameController(*this, true, player_nr));406 set_game_controller(new SinglePlayerGameController(*this, true, player_nr));
429 try {407 try {
430 bool const result = run(&loader_ui, Loaded, script_to_run, false);408 bool const result = run(&loader_ui, Loaded, script_to_run, false, "single_player");
431 delete m_ctrl;409 delete m_ctrl;
432 m_ctrl = nullptr;410 m_ctrl = nullptr;
433 return result;411 return result;
@@ -448,12 +426,7 @@
448void Game::postload()426void Game::postload()
449{427{
450 EditorGameBase::postload();428 EditorGameBase::postload();
451429 get_ibase()->postload();
452 if (g_gr) {
453 assert(get_ibase() != nullptr);
454 get_ibase()->postload();
455 } else
456 log("Note: Widelands runs without graphics, probably in dedicated server mode!\n");
457}430}
458431
459432
@@ -473,13 +446,13 @@
473 * 3. After this has happened, the game graphics are loaded.446 * 3. After this has happened, the game graphics are loaded.
474 *447 *
475 * \return true if a game actually took place, false otherwise448 * \return true if a game actually took place, false otherwise
476 *
477 * \note loader_ui can be nullptr, if this is run as dedicated server.
478 */449 */
479bool Game::run450bool Game::run
480 (UI::ProgressWindow * loader_ui, StartGameType const start_game_type,451 (UI::ProgressWindow * loader_ui, StartGameType const start_game_type,
481 const std::string& script_to_run, bool replay)452 const std::string& script_to_run, bool replay, const std::string& prefix_for_replays)
482{453{
454 assert(loader_ui != nullptr);
455
483 m_replay = replay;456 m_replay = replay;
484 postload();457 postload();
485458
@@ -545,16 +518,13 @@
545518
546 if (m_writereplay || m_writesyncstream) {519 if (m_writereplay || m_writesyncstream) {
547 // Derive a replay filename from the current time520 // Derive a replay filename from the current time
548 std::string fname(REPLAY_DIR);521 const std::string fname = (boost::format("%s/%s_%s%s") % REPLAY_DIR % timestring() %
549 fname += '/';522 prefix_for_replays % REPLAY_SUFFIX).str();
550 fname += timestring();
551 fname += REPLAY_SUFFIX;
552
553 if (m_writereplay) {523 if (m_writereplay) {
554 log("Starting replay writer\n");524 log("Starting replay writer\n");
555525
556 assert(!m_replaywriter);526 assert(!m_replaywriter);
557 m_replaywriter = new ReplayWriter(*this, fname);527 m_replaywriter.reset(new ReplayWriter(*this, fname));
558528
559 log("Replay writer has started\n");529 log("Replay writer has started\n");
560 }530 }
@@ -565,46 +535,30 @@
565535
566 sync_reset();536 sync_reset();
567537
568 if (loader_ui) {538 load_graphics(*loader_ui);
569 load_graphics(*loader_ui);
570539
571#ifdef _WIN32540#ifdef _WIN32
572 // Clear the event queue before starting game because we don't want541 // Clear the event queue before starting game because we don't want
573 // to handle events at game start that happened during loading procedure.542 // to handle events at game start that happened during loading procedure.
574 SDL_Event event;543 SDL_Event event;
575 while (SDL_PollEvent(&event));544 while (SDL_PollEvent(&event));
576#endif545#endif
577546
578 g_sound_handler.change_music("ingame", 1000, 0);547 g_sound_handler.change_music("ingame", 1000, 0);
579548
580 m_state = gs_running;549 m_state = gs_running;
581550
582 get_ibase()->run<UI::Panel::Returncodes>();551 get_ibase()->run<UI::Panel::Returncodes>();
583552
584 m_state = gs_ending;553 m_state = gs_ending;
585554
586 g_sound_handler.change_music("menu", 1000, 0);555 g_sound_handler.change_music("menu", 1000, 0);
587556
588 cleanup_objects();557 cleanup_objects();
589 delete get_ibase();558 delete get_ibase();
590 set_ibase(nullptr);559 set_ibase(nullptr);
591560
592 m_state = gs_notrunning;561 m_state = gs_notrunning;
593 } else {
594 // dedicated server
595 m_state = gs_running;
596 //handle network
597 while (m_state == gs_running) {
598 // TODO(unknown): this should be improved.
599#ifndef _WIN32
600 if (usleep(100) == -1)
601 break;
602#else
603 Sleep(1);
604#endif
605 think();
606 }
607 }
608562
609 return true;563 return true;
610}564}
@@ -634,12 +588,6 @@
634 }588 }
635}589}
636590
637/// (Only) called by the dedicated server, to end a game once all players left
638void Game::end_dedicated_game() {
639 assert(!g_gr);
640 m_state = gs_notrunning;
641}
642
643/**591/**
644 * Cleanup for load592 * Cleanup for load
645 * \deprecated593 * \deprecated
646594
=== modified file 'src/logic/game.h'
--- src/logic/game.h 2016-02-04 14:00:35 +0000
+++ src/logic/game.h 2016-02-07 08:11:43 +0000
@@ -20,6 +20,8 @@
20#ifndef WL_LOGIC_GAME_H20#ifndef WL_LOGIC_GAME_H
21#define WL_LOGIC_GAME_H21#define WL_LOGIC_GAME_H
2222
23#include <memory>
24
23#include "base/md5.h"25#include "base/md5.h"
24#include "io/streamwrite.h"26#include "io/streamwrite.h"
25#include "logic/cmd_queue.h"27#include "logic/cmd_queue.h"
@@ -108,7 +110,12 @@
108 void init_newgame (UI::ProgressWindow* loader_ui, const GameSettings&);110 void init_newgame (UI::ProgressWindow* loader_ui, const GameSettings&);
109 void init_savegame(UI::ProgressWindow* loader_ui, const GameSettings&);111 void init_savegame(UI::ProgressWindow* loader_ui, const GameSettings&);
110 enum StartGameType {NewSPScenario, NewNonScenario, Loaded, NewMPScenario};112 enum StartGameType {NewSPScenario, NewNonScenario, Loaded, NewMPScenario};
111 bool run(UI::ProgressWindow* loader_ui, StartGameType, const std::string& script_to_run, bool replay);113
114 bool run(UI::ProgressWindow* loader_ui,
115 StartGameType,
116 const std::string& script_to_run,
117 bool replay,
118 const std::string& prefix_for_replays);
112119
113 // Returns the upcasted lua interface.120 // Returns the upcasted lua interface.
114 LuaGameInterface& lua() override;121 LuaGameInterface& lua() override;
@@ -127,14 +134,15 @@
127134
128 void think() override;135 void think() override;
129136
130 ReplayWriter * get_replaywriter() {return m_replaywriter;}137 ReplayWriter* get_replaywriter() {
138 return m_replaywriter.get();
139 }
131140
132 /**141 /**
133 * \return \c true if the game is completely loaded and running (or paused)142 * \return \c true if the game is completely loaded and running (or paused)
134 * or \c false otherwise.143 * or \c false otherwise.
135 */144 */
136 bool is_loaded() {return m_state == gs_running;}145 bool is_loaded() {return m_state == gs_running;}
137 void end_dedicated_game();
138146
139 void cleanup_for_load() override;147 void cleanup_for_load() override;
140148
@@ -217,7 +225,6 @@
217 m_target (target),225 m_target (target),
218 m_counter (0),226 m_counter (0),
219 m_next_diskspacecheck(0),227 m_next_diskspacecheck(0),
220 m_dump (nullptr),
221 m_syncstreamsave(false)228 m_syncstreamsave(false)
222 {}229 {}
223230
@@ -238,7 +245,7 @@
238 StreamWrite & m_target;245 StreamWrite & m_target;
239 uint32_t m_counter;246 uint32_t m_counter;
240 uint32_t m_next_diskspacecheck;247 uint32_t m_next_diskspacecheck;
241 ::StreamWrite * m_dump;248 std::unique_ptr<::StreamWrite> m_dump;
242 std::string m_dumpfname;249 std::string m_dumpfname;
243 bool m_syncstreamsave;250 bool m_syncstreamsave;
244 } m_syncwrapper;251 } m_syncwrapper;
@@ -263,8 +270,7 @@
263270
264 SaveHandler m_savehandler;271 SaveHandler m_savehandler;
265272
266 ReplayReader * m_replayreader;273 std::unique_ptr<ReplayWriter> m_replaywriter;
267 ReplayWriter * m_replaywriter;
268274
269 GeneralStatsVector m_general_stats;275 GeneralStatsVector m_general_stats;
270276
271277
=== modified file 'src/logic/game_settings.h'
--- src/logic/game_settings.h 2016-01-28 05:24:34 +0000
+++ src/logic/game_settings.h 2016-02-07 08:11:43 +0000
@@ -67,12 +67,6 @@
67 bool ready; // until now only used as a check for whether user is currently receiving a file or not67 bool ready; // until now only used as a check for whether user is currently receiving a file or not
68};68};
6969
70struct DedicatedMapInfos {
71 std::string path;
72 uint8_t players;
73 bool scenario;
74};
75
76/**70/**
77 * Holds all settings about a game that can be configured before the71 * Holds all settings about a game that can be configured before the
78 * game actually starts.72 * game actually starts.
@@ -130,11 +124,6 @@
130124
131 /// Users connected to the game (0-based indices) - only used in multiplayer125 /// Users connected to the game (0-based indices) - only used in multiplayer
132 std::vector<UserSettings> users;126 std::vector<UserSettings> users;
133
134 /// Only used for dedicated servers so the clients can look through the maps available on the server
135 /// like in their "own" map / saved games selection menu
136 std::vector<DedicatedMapInfos> maps;
137 std::vector<DedicatedMapInfos> saved_games;
138};127};
139128
140129
141130
=== modified file 'src/main.cc'
--- src/main.cc 2016-01-22 20:02:04 +0000
+++ src/main.cc 2016-02-07 08:11:43 +0000
@@ -22,10 +22,6 @@
22#include <typeinfo>22#include <typeinfo>
2323
24#include <SDL_main.h>24#include <SDL_main.h>
25#ifndef _WIN32
26#include <fcntl.h>
27#include <syslog.h>
28#endif
29#include <unistd.h>25#include <unistd.h>
3026
31#include "base/log.h"27#include "base/log.h"
@@ -45,59 +41,6 @@
45 */41 */
46int main(int argc, char * argv[])42int main(int argc, char * argv[])
47{43{
48
49#ifndef _WIN32
50 // if Widelands is called as dedicated server, Widelands should be forked and started as daemon
51 bool dedicated = false;
52 bool daemon = false;
53
54 for (int i = 1; i < argc && !(daemon && dedicated); ++i) {
55 std::string opt = argv[i];
56
57 // At least a size of 8 is needed for --daemon, --dedicated is even longer
58 if (opt.size() < 8)
59 continue;
60
61 if (opt == "--version") {
62 cout << "Widelands " << build_id() << '(' << build_type() << ')' << "\n";
63 return 0;
64 }
65
66 std::string::size_type const pos = opt.find('=');
67 if (pos == std::string::npos) { // if no equals sign found
68 if (opt == "--daemon")
69 daemon = true;
70 } else {
71 opt.erase(pos, opt.size() - pos);
72 if (opt == "--dedicated")
73 dedicated = true;
74 }
75 }
76 if (daemon && dedicated) {
77 pid_t pid;
78 if ((pid = fork()) < 0) {
79 perror("fork() failed");
80 exit(2);
81 }
82 if (pid == 0) {
83 setsid();
84
85 close(STDIN_FILENO);
86 close(STDOUT_FILENO);
87 close(STDERR_FILENO);
88
89 open("/dev/null", O_RDWR);
90 dup(STDIN_FILENO);
91 dup(STDIN_FILENO);
92 // from now on, it's a daemon
93 openlog("FREELINE", LOG_PID, LOG_DAEMON);
94 } else {
95 log("Child has PID %i.\n", pid);
96 return 0;
97 }
98 }
99#endif
100
101 WLApplication * g_app = nullptr;44 WLApplication * g_app = nullptr;
102 try {45 try {
103 g_app = WLApplication::get(argc, const_cast<char const * *>(argv));46 g_app = WLApplication::get(argc, const_cast<char const * *>(argv));
10447
=== modified file 'src/map_io/map_building_packet.cc'
--- src/map_io/map_building_packet.cc 2016-01-29 15:09:06 +0000
+++ src/map_io/map_building_packet.cc 2016-02-07 08:11:43 +0000
@@ -99,8 +99,7 @@
99 read_priorities (*building, fr);99 read_priorities (*building, fr);
100100
101 // Reference the players tribe if in editor.101 // Reference the players tribe if in editor.
102 if (g_gr) // but not on dedicated servers ;)102 ibase.reference_player_tribe(p, &tribe);
103 ibase.reference_player_tribe(p, &tribe);
104 } else103 } else
105 throw GameDataError("player %u does not exist", p);104 throw GameDataError("player %u does not exist", p);
106 }105 }
107106
=== modified file 'src/network/CMakeLists.txt'
--- src/network/CMakeLists.txt 2015-01-31 16:03:59 +0000
+++ src/network/CMakeLists.txt 2016-02-07 08:11:43 +0000
@@ -32,7 +32,6 @@
32 chat32 chat
33 game_io33 game_io
34 helper34 helper
35 io_dedicated_log
36 io_fileread35 io_fileread
37 io_filesystem36 io_filesystem
38 io_stream37 io_stream
3938
=== modified file 'src/network/internet_gaming.cc'
--- src/network/internet_gaming.cc 2015-10-25 15:44:36 +0000
+++ src/network/internet_gaming.cc 2016-02-07 08:11:43 +0000
@@ -26,7 +26,6 @@
26#include "base/log.h"26#include "base/log.h"
27#include "base/macros.h"27#include "base/macros.h"
28#include "base/warning.h"28#include "base/warning.h"
29#include "io/dedicated_log.h"
30#include "io/fileread.h"29#include "io/fileread.h"
31#include "io/filesystem/layered_filesystem.h"30#include "io/filesystem/layered_filesystem.h"
32#include "network/internet_gaming_messages.h"31#include "network/internet_gaming_messages.h"
@@ -103,7 +102,7 @@
103102
104void InternetGaming::initialize_connection() {103void InternetGaming::initialize_connection() {
105 // First of all try to connect to the metaserver104 // First of all try to connect to the metaserver
106 dedicatedlog("InternetGaming: Connecting to the metaserver.\n");105 log("InternetGaming: Connecting to the metaserver.\n");
107 IPaddress peer;106 IPaddress peer;
108 if (hostent * const he = gethostbyname(m_meta.c_str())) {107 if (hostent * const he = gethostbyname(m_meta.c_str())) {
109 peer.host = (reinterpret_cast<in_addr *>(he->h_addr_list[0]))->s_addr;108 peer.host = (reinterpret_cast<in_addr *>(he->h_addr_list[0]))->s_addr;
@@ -147,7 +146,7 @@
147 initialize_connection();146 initialize_connection();
148147
149 // If we are here, a connection was established and we can send our login package through the socket.148 // If we are here, a connection was established and we can send our login package through the socket.
150 dedicatedlog("InternetGaming: Sending login request.\n");149 log("InternetGaming: Sending login request.\n");
151 SendPacket s;150 SendPacket s;
152 s.string(IGPCMD_LOGIN);151 s.string(IGPCMD_LOGIN);
153 s.string(boost::lexical_cast<std::string>(INTERNET_GAMING_PROTOCOL_VERSION));152 s.string(boost::lexical_cast<std::string>(INTERNET_GAMING_PROTOCOL_VERSION));
@@ -174,7 +173,7 @@
174 return false;173 return false;
175 }174 }
176 }175 }
177 dedicatedlog("InternetGaming: No answer from metaserver!\n");176 log("InternetGaming: No answer from metaserver!\n");
178 logout("NO_ANSWER");177 logout("NO_ANSWER");
179 return false;178 return false;
180}179}
@@ -191,7 +190,7 @@
191 initialize_connection();190 initialize_connection();
192191
193 // If we are here, a connection was established and we can send our login package through the socket.192 // If we are here, a connection was established and we can send our login package through the socket.
194 dedicatedlog("InternetGaming: Sending relogin request.\n");193 log("InternetGaming: Sending relogin request.\n");
195 SendPacket s;194 SendPacket s;
196 s.string(IGPCMD_RELOGIN);195 s.string(IGPCMD_RELOGIN);
197 s.string(boost::lexical_cast<std::string>(INTERNET_GAMING_PROTOCOL_VERSION));196 s.string(boost::lexical_cast<std::string>(INTERNET_GAMING_PROTOCOL_VERSION));
@@ -218,7 +217,7 @@
218 }217 }
219218
220 if (INTERNET_GAMING_TIMEOUT <= time(nullptr) - secs) {219 if (INTERNET_GAMING_TIMEOUT <= time(nullptr) - secs) {
221 dedicatedlog("InternetGaming: No answer from metaserver!\n");220 log("InternetGaming: No answer from metaserver!\n");
222 return false;221 return false;
223 }222 }
224223
@@ -249,7 +248,7 @@
249 s.send(m_sock);248 s.send(m_sock);
250249
251 const std::string & msg = InternetGamingMessages::get_message(msgcode);250 const std::string & msg = InternetGamingMessages::get_message(msgcode);
252 dedicatedlog("InternetGaming: logout(%s)\n", msg.c_str());251 log("InternetGaming: logout(%s)\n", msg.c_str());
253 format_and_add_chat("", "", true, msg);252 format_and_add_chat("", "", true, msg);
254253
255 reset();254 reset();
@@ -269,7 +268,7 @@
269 if (!m_deserializer.read(m_sock)) {268 if (!m_deserializer.read(m_sock)) {
270 set_error();269 set_error();
271 const std::string & msg = InternetGamingMessages::get_message("CONNECTION_LOST");270 const std::string & msg = InternetGamingMessages::get_message("CONNECTION_LOST");
272 dedicatedlog("InternetGaming: Error: %s\n", msg.c_str());271 log("InternetGaming: Error: %s\n", msg.c_str());
273 format_and_add_chat("", "", true, msg);272 format_and_add_chat("", "", true, msg);
274273
275 // Check how much time passed since the socket broke the last time274 // Check how much time passed since the socket broke the last time
@@ -331,7 +330,7 @@
331 if (now > waittimeout) {330 if (now > waittimeout) {
332 set_error();331 set_error();
333 waittimeout = std::numeric_limits<int32_t>::max();332 waittimeout = std::numeric_limits<int32_t>::max();
334 dedicatedlog("InternetGaming: reached a timeout for an awaited answer of the metaserver!\n");333 log("InternetGaming: reached a timeout for an awaited answer of the metaserver!\n");
335 if (!relogin()) {334 if (!relogin()) {
336 // Do not try to relogin again automatically.335 // Do not try to relogin again automatically.
337 reset();336 reset();
@@ -383,20 +382,20 @@
383 m_clientname = packet.string();382 m_clientname = packet.string();
384 m_clientrights = packet.string();383 m_clientrights = packet.string();
385 m_state = LOBBY;384 m_state = LOBBY;
386 dedicatedlog("InternetGaming: Client %s logged in.\n", m_clientname.c_str());385 log("InternetGaming: Client %s logged in.\n", m_clientname.c_str());
387 return;386 return;
388387
389 } else if (cmd == IGPCMD_RELOGIN) {388 } else if (cmd == IGPCMD_RELOGIN) {
390 // Clients request to relogin was granted389 // Clients request to relogin was granted
391 m_state = LOBBY;390 m_state = LOBBY;
392 dedicatedlog("InternetGaming: Client %s relogged in.\n", m_clientname.c_str());391 log("InternetGaming: Client %s relogged in.\n", m_clientname.c_str());
393 format_and_add_chat("", "", true, _("Successfully reconnected to the metaserver!"));392 format_and_add_chat("", "", true, _("Successfully reconnected to the metaserver!"));
394 return;393 return;
395394
396 } else if (cmd == IGPCMD_ERROR) {395 } else if (cmd == IGPCMD_ERROR) {
397 std::string errortype = packet.string();396 std::string errortype = packet.string();
398 if (errortype != "LOGIN" && errortype != "RELOGIN") {397 if (errortype != "LOGIN" && errortype != "RELOGIN") {
399 dedicatedlog("InternetGaming: Strange ERROR in connecting state: %s\n", errortype.c_str());398 log("InternetGaming: Strange ERROR in connecting state: %s\n", errortype.c_str());
400 throw WLWarning(_("Mixed up"), _("The metaserver sent a strange ERROR during connection"));399 throw WLWarning(_("Mixed up"), _("The metaserver sent a strange ERROR during connection"));
401 }400 }
402 // Clients login request got rejected401 // Clients login request got rejected
@@ -419,7 +418,7 @@
419 try {418 try {
420 if (cmd == IGPCMD_LOGIN || cmd == IGPCMD_RELOGIN) {419 if (cmd == IGPCMD_LOGIN || cmd == IGPCMD_RELOGIN) {
421 // Login specific commands but not in CONNECTING state...420 // Login specific commands but not in CONNECTING state...
422 dedicatedlog421 log
423 ("InternetGaming: Received %s cmd although client is not in CONNECTING state.\n", cmd.c_str());422 ("InternetGaming: Received %s cmd although client is not in CONNECTING state.\n", cmd.c_str());
424 std::string temp =423 std::string temp =
425 (boost::format424 (boost::format
@@ -431,7 +430,7 @@
431 else if (cmd == IGPCMD_TIME) {430 else if (cmd == IGPCMD_TIME) {
432 // Client received the server time431 // Client received the server time
433 time_offset = boost::lexical_cast<int>(packet.string()) - time(nullptr);432 time_offset = boost::lexical_cast<int>(packet.string()) - time(nullptr);
434 dedicatedlog433 log
435 (ngettext434 (ngettext
436 ("InternetGaming: Server time offset is %u second.",435 ("InternetGaming: Server time offset is %u second.",
437 "InternetGaming: Server time offset is %u seconds.", time_offset),436 "InternetGaming: Server time offset is %u seconds.", time_offset),
@@ -471,7 +470,7 @@
471470
472 else if (cmd == IGPCMD_GAMES_UPDATE) {471 else if (cmd == IGPCMD_GAMES_UPDATE) {
473 // Client received a note, that the list of games was changed472 // Client received a note, that the list of games was changed
474 dedicatedlog("InternetGaming: Game update on metaserver.\n");473 log("InternetGaming: Game update on metaserver.\n");
475 gameupdateonmetaserver = true;474 gameupdateonmetaserver = true;
476 }475 }
477476
@@ -480,7 +479,7 @@
480 uint8_t number = boost::lexical_cast<int>(packet.string()) & 0xff;479 uint8_t number = boost::lexical_cast<int>(packet.string()) & 0xff;
481 std::vector<InternetGame> old = gamelist;480 std::vector<InternetGame> old = gamelist;
482 gamelist.clear();481 gamelist.clear();
483 dedicatedlog("InternetGaming: Received a game list update with %u items.\n", number);482 log("InternetGaming: Received a game list update with %u items.\n", number);
484 for (uint8_t i = 0; i < number; ++i) {483 for (uint8_t i = 0; i < number; ++i) {
485 InternetGame * ing = new InternetGame();484 InternetGame * ing = new InternetGame();
486 ing->name = packet.string();485 ing->name = packet.string();
@@ -513,7 +512,7 @@
513512
514 else if (cmd == IGPCMD_CLIENTS_UPDATE) {513 else if (cmd == IGPCMD_CLIENTS_UPDATE) {
515 // Client received a note, that the list of clients was changed514 // Client received a note, that the list of clients was changed
516 dedicatedlog("InternetGaming: Client update on metaserver.\n");515 log("InternetGaming: Client update on metaserver.\n");
517 clientupdateonmetaserver = true;516 clientupdateonmetaserver = true;
518 }517 }
519518
@@ -522,7 +521,7 @@
522 uint8_t number = boost::lexical_cast<int>(packet.string()) & 0xff;521 uint8_t number = boost::lexical_cast<int>(packet.string()) & 0xff;
523 std::vector<InternetClient> old = clientlist;522 std::vector<InternetClient> old = clientlist;
524 clientlist.clear();523 clientlist.clear();
525 dedicatedlog("InternetGaming: Received a client list update with %u items.\n", number);524 log("InternetGaming: Received a client list update with %u items.\n", number);
526 for (uint8_t i = 0; i < number; ++i) {525 for (uint8_t i = 0; i < number; ++i) {
527 InternetClient * inc = new InternetClient();526 InternetClient * inc = new InternetClient();
528 inc->name = packet.string();527 inc->name = packet.string();
@@ -639,7 +638,7 @@
639 s.string(gamename);638 s.string(gamename);
640 s.send(m_sock);639 s.send(m_sock);
641 m_gamename = gamename;640 m_gamename = gamename;
642 dedicatedlog("InternetGaming: Client tries to join a game with the name %s\n", m_gamename.c_str());641 log("InternetGaming: Client tries to join a game with the name %s\n", m_gamename.c_str());
643 m_state = IN_GAME;642 m_state = IN_GAME;
644643
645644
@@ -660,7 +659,7 @@
660 s.string(m_gamename);659 s.string(m_gamename);
661 s.string("1024"); // Used to be maxclients, no longer used.660 s.string("1024"); // Used to be maxclients, no longer used.
662 s.send(m_sock);661 s.send(m_sock);
663 dedicatedlog("InternetGaming: Client opened a game with the name %s.\n", m_gamename.c_str());662 log("InternetGaming: Client opened a game with the name %s.\n", m_gamename.c_str());
664 m_state = IN_GAME;663 m_state = IN_GAME;
665664
666 // From now on we wait for a reply from the metaserver665 // From now on we wait for a reply from the metaserver
@@ -678,7 +677,7 @@
678 SendPacket s;677 SendPacket s;
679 s.string(IGPCMD_GAME_START);678 s.string(IGPCMD_GAME_START);
680 s.send(m_sock);679 s.send(m_sock);
681 dedicatedlog("InternetGaming: Client announced the start of the game %s.\n", m_gamename.c_str());680 log("InternetGaming: Client announced the start of the game %s.\n", m_gamename.c_str());
682681
683 // From now on we wait for a reply from the metaserver682 // From now on we wait for a reply from the metaserver
684 waitcmd = IGPCMD_GAME_START;683 waitcmd = IGPCMD_GAME_START;
@@ -700,7 +699,7 @@
700 m_gameip = "";699 m_gameip = "";
701 m_state = LOBBY;700 m_state = LOBBY;
702701
703 dedicatedlog("InternetGaming: Client announced the disconnect from the game %s.\n", m_gamename.c_str());702 log("InternetGaming: Client announced the disconnect from the game %s.\n", m_gamename.c_str());
704}703}
705704
706705
707706
=== modified file 'src/network/netclient.cc'
--- src/network/netclient.cc 2016-02-04 14:00:35 +0000
+++ src/network/netclient.cc 2016-02-07 08:11:43 +0000
@@ -100,7 +100,7 @@
100100
101NetClient::NetClient101NetClient::NetClient
102 (IPaddress * const svaddr, const std::string & playername, bool internet)102 (IPaddress * const svaddr, const std::string & playername, bool internet)
103: d(new NetClientImpl), m_internet(internet), m_dedicated_access(false), m_dedicated_temp_scenario(false)103: d(new NetClientImpl), m_internet(internet)
104{104{
105 d->sock = SDLNet_TCP_Open(svaddr);105 d->sock = SDLNet_TCP_Open(svaddr);
106 if (d->sock == nullptr)106 if (d->sock == nullptr)
@@ -157,17 +157,6 @@
157 d->modal = &lgm;157 d->modal = &lgm;
158 FullscreenMenuBase::MenuTarget code = lgm.run<FullscreenMenuBase::MenuTarget>();158 FullscreenMenuBase::MenuTarget code = lgm.run<FullscreenMenuBase::MenuTarget>();
159 d->modal = nullptr;159 d->modal = nullptr;
160 // Only possible if server is dedicated - client pressed "start game" button
161 if (code == FullscreenMenuBase::MenuTarget::kNormalGame) {
162 SendPacket subs;
163 subs.unsigned_8(NETCMD_LAUNCH);
164 subs.send(d->sock);
165
166 // Reopen the menu - perhaps the start is denied or other problems occur
167 d->modal = &lgm;
168 code = lgm.run<FullscreenMenuBase::MenuTarget>();
169 d->modal = nullptr;
170 }
171 if (code == FullscreenMenuBase::MenuTarget::kBack) {160 if (code == FullscreenMenuBase::MenuTarget::kBack) {
172 // if this is an internet game, tell the metaserver that client is back in the lobby.161 // if this is an internet game, tell the metaserver that client is back in the lobby.
173 if (m_internet)162 if (m_internet)
@@ -190,42 +179,37 @@
190 tipstext.push_back("multiplayer");179 tipstext.push_back("multiplayer");
191 try {180 try {
192 tipstext.push_back(get_players_tribe());181 tipstext.push_back(get_players_tribe());
193 } catch (NoTribe) {}182 } catch (NoTribe) {
194 GameTips tips (*loader_ui, tipstext);183 }
184 GameTips tips(*loader_ui, tipstext);
195185
196 loader_ui->step(_("Preparing game"));186 loader_ui->step(_("Preparing game"));
197187
198 d->game = &game;188 d->game = &game;
199 game.set_game_controller(this);189 game.set_game_controller(this);
200 uint8_t const pn = d->settings.playernum + 1;190 uint8_t const pn = d->settings.playernum + 1;
201 InteractiveGameBase * igb;191 InteractiveGameBase* igb;
202 if (pn > 0)192 if (pn > 0)
203 igb =193 igb = new InteractivePlayer(game, g_options.pull_section("global"), pn, true);
204 new InteractivePlayer
205 (game, g_options.pull_section("global"),
206 pn, true);
207 else194 else
208 igb =195 igb = new InteractiveSpectator(game, g_options.pull_section("global"), true);
209 new InteractiveSpectator
210 (game, g_options.pull_section("global"), true);
211 game.set_ibase(igb);196 game.set_ibase(igb);
212 igb->set_chat_provider(*this);197 igb->set_chat_provider(*this);
213 if (!d->settings.savegame) // new map198 if (!d->settings.savegame) { // new map
214 game.init_newgame(loader_ui, d->settings);199 game.init_newgame(loader_ui, d->settings);
215 else // savegame200 } else { // savegame
216 game.init_savegame(loader_ui, d->settings);201 game.init_savegame(loader_ui, d->settings);
202 }
217 d->time.reset(game.get_gametime());203 d->time.reset(game.get_gametime());
218 d->lasttimestamp = game.get_gametime();204 d->lasttimestamp = game.get_gametime();
219 d->lasttimestamp_realtime = SDL_GetTicks();205 d->lasttimestamp_realtime = SDL_GetTicks();
220206
221 d->modal = game.get_ibase();207 d->modal = game.get_ibase();
222 game.run208 game.run(loader_ui, d->settings.savegame ? Widelands::Game::Loaded : d->settings.scenario ?
223 (loader_ui,209 Widelands::Game::NewMPScenario :
224 d->settings.savegame ?210 Widelands::Game::NewNonScenario,
225 Widelands::Game::Loaded211 "", false,
226 : d->settings.scenario ?212 (boost::format("netclient_%d") % static_cast<int>(d->settings.usernum)).str());
227 Widelands::Game::NewMPScenario : Widelands::Game::NewNonScenario,
228 "", false);
229213
230 // if this is an internet game, tell the metaserver that the game is done.214 // if this is an internet game, tell the metaserver that the game is done.
231 if (m_internet)215 if (m_internet)
@@ -318,38 +302,16 @@
318 return d->settings;302 return d->settings;
319}303}
320304
321void NetClient::set_scenario(bool scenario)305void NetClient::set_scenario(bool) {
322{306}
323 // only accessible, if server is a dedicated server and access is granted307
324 if (!m_dedicated_access)308bool NetClient::can_change_map() {
325 return;309 return false;
326 m_dedicated_temp_scenario = scenario;310}
327}311
328312bool NetClient::can_change_player_state(uint8_t const)
329bool NetClient::can_change_map()313{
330{314 return false;
331 // only true, if server is a dedicated server and access is granted
332 return m_dedicated_access;
333}
334
335bool NetClient::can_change_player_state(uint8_t const number)
336{
337 if (!m_dedicated_access) // normal case
338 return false;
339
340 // dedicated server, access granted
341 if (d->settings.savegame)
342 return d->settings.players.at(number).state != PlayerSettings::stateClosed;
343 else if (d->settings.scenario)
344 return
345 ((d->settings.players.at(number).state == PlayerSettings::stateOpen
346 ||
347 d->settings.players.at(number).state == PlayerSettings::stateHuman)
348 &&
349 d->settings .players.at(number).closeable)
350 ||
351 d->settings .players.at(number).state == PlayerSettings::stateClosed;
352 return true;
353}315}
354316
355bool NetClient::can_change_player_tribe(uint8_t number)317bool NetClient::can_change_player_tribe(uint8_t number)
@@ -359,75 +321,17 @@
359321
360bool NetClient::can_change_player_team(uint8_t number)322bool NetClient::can_change_player_team(uint8_t number)
361{323{
362 if (!m_dedicated_access) // normal case324 return (number == d->settings.playernum) && !d->settings.scenario && !d->settings.savegame;
363 return (number == d->settings.playernum) && !d->settings.scenario && !d->settings.savegame;
364 else { // dedicated server, access granted
365 if (d->settings.scenario || d->settings.savegame)
366 return false;
367 if (number >= d->settings.players.size())
368 return false;
369 if (number == d->settings.playernum)
370 return true;
371 return
372 d->settings.players.at(number).state == PlayerSettings::stateComputer;
373 }
374}325}
375326
376bool NetClient::can_change_player_init(uint8_t number)327bool NetClient::can_change_player_init(uint8_t number)
377{328{
378 if (!m_dedicated_access) // normal case329 return false;
379 return false;
380 else { // dedicated server, access granted
381 if (d->settings.scenario || d->settings.savegame)
382 return false;
383 return number < d->settings.players.size();
384 }
385}330}
386331
387bool NetClient::can_launch()332bool NetClient::can_launch()
388{333{
389 // only true, if server is a dedicated server and access is granted334 return false;
390 if (!m_dedicated_access)
391 return false;
392 if (d->settings.mapname.empty())
393 return false;
394 if (d->settings.players.size() < 1)
395 return false;
396 if (d->game)
397 return false;
398
399 // if there is one client that is currently receiving a file, we can not launch.
400 for (uint8_t i = 0; i < d->settings.users.size(); ++i) {
401 if (d->settings.users[i].position == d->settings.users[i].not_connected())
402 continue;
403 if (!d->settings.users[i].ready)
404 return false;
405 }
406
407 // all players must be connected to a controller (human/ai) or be closed.
408 for (size_t i = 0; i < d->settings.players.size(); ++i) {
409 if (d->settings.players.at(i).state == PlayerSettings::stateOpen)
410 return false;
411 }
412 return true;
413}
414
415void NetClient::set_map
416 (const std::string & name,
417 const std::string & path,
418 uint32_t /* players */,
419 bool savegame)
420{
421 // only accessible, if server is a dedicated server and access is granted
422 if (!m_dedicated_access)
423 return;
424 SendPacket s;
425 s.unsigned_8(NETCMD_SETTING_MAP);
426 s.string(name);
427 s.string(path);
428 s.unsigned_8(savegame ? 1 : 0);
429 s.unsigned_8(m_dedicated_temp_scenario ? 1 : 0);
430 s.send(d->sock);
431}335}
432336
433void NetClient::set_player_state(uint8_t, PlayerSettings::State)337void NetClient::set_player_state(uint8_t, PlayerSettings::State)
@@ -442,18 +346,16 @@
442346
443void NetClient::next_player_state(uint8_t number)347void NetClient::next_player_state(uint8_t number)
444{348{
445 // only accessible, if server is a dedicated server and access is granted349 // client is not allowed to do this
446 if (!m_dedicated_access)350}
447 return;351
448 SendPacket s;352void NetClient::set_map(const std::string&, const std::string&, uint32_t, bool) {
449 s.unsigned_8(NETCMD_SETTING_PLAYER);353 // client is not allowed to do this
450 s.unsigned_8(number);
451 s.send(d->sock);
452}354}
453355
454void NetClient::set_player_tribe(uint8_t number, const std::string & tribe, bool const random_tribe)356void NetClient::set_player_tribe(uint8_t number, const std::string & tribe, bool const random_tribe)
455{357{
456 if ((number != d->settings.playernum) && !m_dedicated_access)358 if ((number != d->settings.playernum))
457 return;359 return;
458360
459 SendPacket s;361 SendPacket s;
@@ -466,7 +368,7 @@
466368
467void NetClient::set_player_team(uint8_t number, Widelands::TeamNumber team)369void NetClient::set_player_team(uint8_t number, Widelands::TeamNumber team)
468{370{
469 if ((number != d->settings.playernum) && !m_dedicated_access)371 if ((number != d->settings.playernum))
470 return;372 return;
471373
472 SendPacket s;374 SendPacket s;
@@ -483,7 +385,7 @@
483385
484void NetClient::set_player_shared(uint8_t number, uint8_t player)386void NetClient::set_player_shared(uint8_t number, uint8_t player)
485{387{
486 if ((number != d->settings.playernum) && !m_dedicated_access)388 if ((number != d->settings.playernum))
487 return;389 return;
488390
489 SendPacket s;391 SendPacket s;
@@ -495,7 +397,7 @@
495397
496void NetClient::set_player_init(uint8_t number, uint8_t)398void NetClient::set_player_init(uint8_t number, uint8_t)
497{399{
498 if ((number != d->settings.playernum) && !m_dedicated_access)400 if ((number != d->settings.playernum))
499 return;401 return;
500402
501 // Host will decide what to change, therefore the init is not send, just the request to change403 // Host will decide what to change, therefore the init is not send, just the request to change
@@ -526,12 +428,7 @@
526}428}
527429
528void NetClient::next_win_condition() {430void NetClient::next_win_condition() {
529 // only accessible, if server is a dedicated server and access is granted431 // Clients are not allowed to change this
530 if (!m_dedicated_access)
531 return;
532 SendPacket s;
533 s.unsigned_8(NETCMD_WIN_CONDITION);
534 s.send(d->sock);
535}432}
536433
537void NetClient::set_player_number(uint8_t const number)434void NetClient::set_player_number(uint8_t const number)
@@ -723,23 +620,6 @@
723 break;620 break;
724 }621 }
725622
726 case NETCMD_DEDICATED_MAPS: {
727 DedicatedMapInfos info;
728 info.path = g_fs->FileSystem::fix_cross_file(packet.string());
729 info.players = packet.unsigned_8();
730 info.scenario = packet.unsigned_8() == 1;
731 d->settings.maps.push_back(info);
732 break;
733 }
734
735 case NETCMD_DEDICATED_SAVED_GAMES: {
736 DedicatedMapInfos info;
737 info.path = g_fs->FileSystem::fix_cross_file(packet.string());
738 info.players = packet.unsigned_8();
739 d->settings.saved_games.push_back(info);
740 break;
741 }
742
743 case NETCMD_NEW_FILE_AVAILABLE: {623 case NETCMD_NEW_FILE_AVAILABLE: {
744 std::string path = g_fs->FileSystem::fix_cross_file(packet.string());624 std::string path = g_fs->FileSystem::fix_cross_file(packet.string());
745 uint32_t bytes = packet.unsigned_32();625 uint32_t bytes = packet.unsigned_32();
@@ -839,7 +719,6 @@
839 fr.open(*g_fs, file->filename);719 fr.open(*g_fs, file->filename);
840720
841 std::unique_ptr<char[]> complete(new char[file->bytes]);721 std::unique_ptr<char[]> complete(new char[file->bytes]);
842 if (!complete) throw wexception("Out of memory");
843722
844 fr.data_complete(complete.get(), file->bytes);723 fr.data_complete(complete.get(), file->bytes);
845 SimpleMD5Checksum md5sum;724 SimpleMD5Checksum md5sum;
@@ -952,19 +831,23 @@
952 d->modal->end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kOk);831 d->modal->end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kOk);
953 break;832 break;
954 }833 }
834
955 case NETCMD_SETSPEED:835 case NETCMD_SETSPEED:
956 d->realspeed = packet.unsigned_16();836 d->realspeed = packet.unsigned_16();
957 log837 log
958 ("[Client] speed: %u.%03u\n",838 ("[Client] speed: %u.%03u\n",
959 d->realspeed / 1000, d->realspeed % 1000);839 d->realspeed / 1000, d->realspeed % 1000);
960 break;840 break;
841
961 case NETCMD_TIME:842 case NETCMD_TIME:
962 d->time.receive(packet.signed_32());843 d->time.receive(packet.signed_32());
963 break;844 break;
845
964 case NETCMD_WAIT:846 case NETCMD_WAIT:
965 log("[Client]: server is waiting.\n");847 log("[Client]: server is waiting.\n");
966 d->server_is_waiting = true;848 d->server_is_waiting = true;
967 break;849 break;
850
968 case NETCMD_PLAYERCOMMAND: {851 case NETCMD_PLAYERCOMMAND: {
969 if (!d->game)852 if (!d->game)
970 throw DisconnectException("PLAYERCMD_WO_GAME");853 throw DisconnectException("PLAYERCMD_WO_GAME");
@@ -977,6 +860,7 @@
977 d->time.receive(time);860 d->time.receive(time);
978 break;861 break;
979 }862 }
863
980 case NETCMD_SYNCREQUEST: {864 case NETCMD_SYNCREQUEST: {
981 if (!d->game)865 if (!d->game)
982 throw DisconnectException("SYNCREQUEST_WO_GAME");866 throw DisconnectException("SYNCREQUEST_WO_GAME");
@@ -985,6 +869,7 @@
985 d->game->enqueue_command(new CmdNetCheckSync(time, this));869 d->game->enqueue_command(new CmdNetCheckSync(time, this));
986 break;870 break;
987 }871 }
872
988 case NETCMD_CHAT: {873 case NETCMD_CHAT: {
989 ChatMessage c;874 ChatMessage c;
990 c.time = time(nullptr);875 c.time = time(nullptr);
@@ -997,6 +882,7 @@
997 Notifications::publish(c);882 Notifications::publish(c);
998 break;883 break;
999 }884 }
885
1000 case NETCMD_SYSTEM_MESSAGE_CODE: {886 case NETCMD_SYSTEM_MESSAGE_CODE: {
1001 ChatMessage c;887 ChatMessage c;
1002 c.time = time(nullptr);888 c.time = time(nullptr);
@@ -1011,10 +897,7 @@
1011 Notifications::publish(c);897 Notifications::publish(c);
1012 break;898 break;
1013 }899 }
1014 case NETCMD_DEDICATED_ACCESS: {900
1015 m_dedicated_access = true;
1016 break;
1017 }
1018 case NETCMD_INFO_DESYNC:901 case NETCMD_INFO_DESYNC:
1019 log902 log
1020 ("[Client] received NETCMD_INFO_DESYNC. Trying to salvage some "903 ("[Client] received NETCMD_INFO_DESYNC. Trying to salvage some "
@@ -1022,6 +905,7 @@
1022 if (d->game)905 if (d->game)
1023 d->game->save_syncstream(true);906 d->game->save_syncstream(true);
1024 break;907 break;
908
1025 default:909 default:
1026 throw ProtocolException(cmd);910 throw ProtocolException(cmd);
1027 }911 }
1028912
=== modified file 'src/network/netclient.h'
--- src/network/netclient.h 2014-09-30 06:25:04 +0000
+++ src/network/netclient.h 2016-02-07 08:11:43 +0000
@@ -117,8 +117,6 @@
117117
118 NetClientImpl * d;118 NetClientImpl * d;
119 bool m_internet;119 bool m_internet;
120 bool m_dedicated_access;
121 bool m_dedicated_temp_scenario;
122};120};
123121
124#endif // end of include guard: WL_NETWORK_NETCLIENT_H122#endif // end of include guard: WL_NETWORK_NETCLIENT_H
125123
=== modified file 'src/network/nethost.cc'
--- src/network/nethost.cc 2016-02-04 14:00:35 +0000
+++ src/network/nethost.cc 2016-02-07 08:11:43 +0000
@@ -40,7 +40,6 @@
40#include "game_io/game_loader.h"40#include "game_io/game_loader.h"
41#include "game_io/game_preload_packet.h"41#include "game_io/game_preload_packet.h"
42#include "helper.h"42#include "helper.h"
43#include "io/dedicated_log.h"
44#include "io/fileread.h"43#include "io/fileread.h"
45#include "io/filesystem/layered_filesystem.h"44#include "io/filesystem/layered_filesystem.h"
46#include "logic/game.h"45#include "logic/game.h"
@@ -310,7 +309,7 @@
310struct HostChatProvider : public ChatProvider {309struct HostChatProvider : public ChatProvider {
311 HostChatProvider(NetHost * const _h) : h(_h), kickClient(0) {}310 HostChatProvider(NetHost * const _h) : h(_h), kickClient(0) {}
312311
313 void send(const std::string & msg) override {312 void send(const std::string& msg) override {
314 ChatMessage c;313 ChatMessage c;
315 c.time = time(nullptr);314 c.time = time(nullptr);
316 c.playern = h->get_local_playerposition();315 c.playern = h->get_local_playerposition();
@@ -337,9 +336,9 @@
337336
338 // Split up in "cmd" "arg1" "arg2"337 // Split up in "cmd" "arg1" "arg2"
339 std::string cmd, arg1, arg2;338 std::string cmd, arg1, arg2;
340 std::string temp = c.msg.substr(1); // cut off '/'339 std::string temp = c.msg.substr(1); // cut off '/'
341 h->split_command_array(temp, cmd, arg1, arg2);340 h->split_command_array(temp, cmd, arg1, arg2);
342 dedicatedlog("%s + \"%s\" + \"%s\"\n", cmd.c_str(), arg1.c_str(), arg2.c_str());341 log("%s + \"%s\" + \"%s\"\n", cmd.c_str(), arg1.c_str(), arg2.c_str());
343342
344 // let "/me" pass - handled by chat343 // let "/me" pass - handled by chat
345 if (cmd == "me") {344 if (cmd == "me") {
@@ -354,32 +353,32 @@
354353
355 // Help354 // Help
356 if (cmd == "help") {355 if (cmd == "help") {
357 c.msg =356 c.msg = (boost::format("<br>%s<br>%s<br>%s<br>%s<br>%s<br>%s<br>%s") %
358 (boost::format("<br>%s<br>%s<br>%s<br>%s<br>%s<br>%s<br>%s")357 _("Available host commands are:")
359 % _("Available host commands are:")358 /** TRANSLATORS: Available host command */
360 /** TRANSLATORS: Available host command */359 %
361 % _("/help - Shows this help")360 _("/help - Shows this help")
362 /** TRANSLATORS: Available host command */361 /** TRANSLATORS: Available host command */
363 % _("/announce <msg> - Send a chatmessage as announcement (system chat)")362 %
364 /** TRANSLATORS: Available host command */363 _("/announce <msg> - Send a chatmessage as announcement (system chat)")
365 % _("/warn <name> <reason> - Warn the user <name> because of <reason>")364 /** TRANSLATORS: Available host command */
366 /** TRANSLATORS: Available host command */365 %
367 % _("/kick <name> <reason> - Kick the user <name> because of <reason>")366 _("/warn <name> <reason> - Warn the user <name> because of <reason>")
368 /** TRANSLATORS: Available host command */367 /** TRANSLATORS: Available host command */
369 % _("/forcePause - Force the game to pause.")368 %
370 /** TRANSLATORS: Available host command */369 _("/kick <name> <reason> - Kick the user <name> because of <reason>")
371 % _("/endForcedPause - Return game to normal speed.")370 /** TRANSLATORS: Available host command */
372 ).str();371 %
373 if (!h->is_dedicated())372 _("/forcePause - Force the game to pause.")
374 c.recipient = h->get_local_playername();373 /** TRANSLATORS: Available host command */
374 %
375 _("/endForcedPause - Return game to normal speed.")).str();
375 }376 }
376377
377 // Announce378 // Announce
378 else if (cmd == "announce") {379 else if (cmd == "announce") {
379 if (arg1.empty()) {380 if (arg1.empty()) {
380 c.msg = _("Wrong use, should be: /announce <message>");381 c.msg = _("Wrong use, should be: /announce <message>");
381 if (!h->is_dedicated())
382 c.recipient = h->get_local_playername();
383 } else {382 } else {
384 if (arg2.size())383 if (arg2.size())
385 arg1 += " " + arg2;384 arg1 += " " + arg2;
@@ -391,22 +390,12 @@
391 else if (cmd == "warn") {390 else if (cmd == "warn") {
392 if (arg1.empty() || arg2.empty()) {391 if (arg1.empty() || arg2.empty()) {
393 c.msg = _("Wrong use, should be: /warn <name> <reason>");392 c.msg = _("Wrong use, should be: /warn <name> <reason>");
394 if (!h->is_dedicated())
395 c.recipient = h->get_local_playername();
396 } else {393 } else {
397 int32_t num = h->check_client(arg1);394 int32_t num = h->check_client(arg1);
398 if (num == -2) {395 if (num == -1) {
399 if (!h->is_dedicated()) {
400 c.recipient = h->get_local_playername();
401 c.msg = _("Why would you warn yourself?");
402 } else
403 c.msg = _("Why would you want to warn the dedicated server?");
404 } else if (num == -1) {
405 if (!h->is_dedicated())
406 c.recipient = h->get_local_playername();
407 c.msg = (boost::format(_("The client %s could not be found.")) % arg1).str();396 c.msg = (boost::format(_("The client %s could not be found.")) % arg1).str();
408 } else {397 } else {
409 c.msg = (boost::format("HOST WARNING FOR %s: ") % arg1).str();398 c.msg = (boost::format("HOST WARNING FOR %s: ") % arg1).str();
410 c.msg += arg2;399 c.msg += arg2;
411 }400 }
412 }401 }
@@ -424,22 +413,19 @@
424 kickReason = "No reason given!";413 kickReason = "No reason given!";
425 // Check if client exists414 // Check if client exists
426 int32_t num = h->check_client(kickUser);415 int32_t num = h->check_client(kickUser);
427 if (num == -2)416 if (num == -2) {
428 if (!h->is_dedicated()) {417 c.msg = _("You can not kick yourself!");
429 c.msg = _("You can not kick yourself!");418 } else if (num == -1) {
430 } else
431 c.msg = _("You can not kick the dedicated server");
432 else if (num == -1)
433 c.msg = (boost::format(_("The client %s could not be found.")) % arg1).str();419 c.msg = (boost::format(_("The client %s could not be found.")) % arg1).str();
434 else {420 } else {
435 kickClient = num;421 kickClient = num;
436 c.msg = (boost::format(_("Are you sure you want to kick %s?")) % arg1).str() + "<br>";422 c.msg =
437 c.msg += (boost::format(_("The stated reason was: %s")) % kickReason).str() + "<br>";423 (boost::format(_("Are you sure you want to kick %s?")) % arg1).str() + "<br>";
424 c.msg +=
425 (boost::format(_("The stated reason was: %s")) % kickReason).str() + "<br>";
438 c.msg += (boost::format(_("If yes, type: /ack_kick %s")) % arg1).str();426 c.msg += (boost::format(_("If yes, type: /ack_kick %s")) % arg1).str();
439 }427 }
440 }428 }
441 if (!h->is_dedicated())
442 c.recipient = h->get_local_playername();
443 }429 }
444430
445 // Acknowledge kick431 // Acknowledge kick
@@ -455,18 +441,14 @@
455 } else441 } else
456 c.msg = _("kick acknowledgement cancelled: Wrong name given!");442 c.msg = _("kick acknowledgement cancelled: Wrong name given!");
457 }443 }
458 kickUser = "";444 kickUser = "";
459 kickReason = "";445 kickReason = "";
460 if (!h->is_dedicated())
461 c.recipient = h->get_local_playername();
462 }446 }
463447
464 // Force Pause448 // Force Pause
465 else if (cmd == "forcePause") {449 else if (cmd == "forcePause") {
466 if (h->forced_pause()) {450 if (h->forced_pause()) {
467 c.msg = _("Pause was already forced - game should be paused.");451 c.msg = _("Pause was already forced - game should be paused.");
468 if (!h->is_dedicated())
469 c.recipient = h->get_local_playername();
470 } else {452 } else {
471 c.msg = "HOST FORCED THE GAME TO PAUSE!";453 c.msg = "HOST FORCED THE GAME TO PAUSE!";
472 h->force_pause();454 h->force_pause();
@@ -477,8 +459,6 @@
477 else if (cmd == "endForcedPause") {459 else if (cmd == "endForcedPause") {
478 if (!h->forced_pause()) {460 if (!h->forced_pause()) {
479 c.msg = _("There is no forced pause - nothing to end.");461 c.msg = _("There is no forced pause - nothing to end.");
480 if (!h->is_dedicated())
481 c.recipient = h->get_local_playername();
482 } else {462 } else {
483 c.msg = "HOST ENDED THE FORCED GAME PAUSE!";463 c.msg = "HOST ENDED THE FORCED GAME PAUSE!";
484 h->end_forced_pause();464 h->end_forced_pause();
@@ -488,8 +468,6 @@
488 // Default468 // Default
489 else {469 else {
490 c.msg = _("Invalid command! Type /help for a list of commands.");470 c.msg = _("Invalid command! Type /help for a list of commands.");
491 if (!h->is_dedicated())
492 c.recipient = h->get_local_playername();
493 }471 }
494 }472 }
495 h->send(c);473 h->send(c);
@@ -522,7 +500,6 @@
522 bool syncreport_arrived;500 bool syncreport_arrived;
523 int32_t time; // last time report501 int32_t time; // last time report
524 uint32_t desiredspeed;502 uint32_t desiredspeed;
525 bool dedicated_access;
526 time_t hung_since;503 time_t hung_since;
527 /// The delta time where the last information about the hung client was sent to the other clients relative504 /// The delta time where the last information about the hung client was sent to the other clients relative
528 /// to when the last answer of the client was received.505 /// to when the last answer of the client was received.
@@ -545,9 +522,6 @@
545 /// order as players. In fact, a client must not be assigned to a player.522 /// order as players. In fact, a client must not be assigned to a player.
546 std::vector<Client> clients;523 std::vector<Client> clients;
547524
548 /// Set to true, once the dedicated server should start
549 bool dedicated_start;
550
551 /// The game itself; only non-null while game is running525 /// The game itself; only non-null while game is running
552 Widelands::Game * game;526 Widelands::Game * game;
553527
@@ -603,7 +577,6 @@
603 syncreport_time(0),577 syncreport_time(0),
604 syncreport_arrived(false)578 syncreport_arrived(false)
605 {579 {
606 dedicated_start = false;
607 }580 }
608};581};
609582
@@ -611,12 +584,9 @@
611 :584 :
612 d(new NetHostImpl(this)),585 d(new NetHostImpl(this)),
613 m_internet(internet),586 m_internet(internet),
614 m_is_dedicated(false),
615 m_password(""),
616 m_dedicated_motd(""),
617 m_forced_pause(false)587 m_forced_pause(false)
618{588{
619 dedicatedlog("[Host]: starting up.\n");589 log("[Host]: starting up.\n");
620590
621 if (internet) {591 if (internet) {
622 InternetGaming::ref().open_game();592 InternetGaming::ref().open_game();
@@ -711,79 +681,18 @@
711 }681 }
712}682}
713683
714void NetHost::run(bool const autorun)684void NetHost::run()
715{685{
716 m_is_dedicated = autorun;
717 // Fill the list of possible system messages686 // Fill the list of possible system messages
718 NetworkGamingMessages::fill_map();687 NetworkGamingMessages::fill_map();
719 if (m_is_dedicated) {688 FullscreenMenuLaunchMPG lm(&d->hp, this);
720 // Initializing689 lm.set_chat_provider(d->chat);
721 d->hp.next_win_condition();690 const FullscreenMenuBase::MenuTarget code = lm.run<FullscreenMenuBase::MenuTarget>();
722 // May be the server is password protected?691 if (code == FullscreenMenuBase::MenuTarget::kBack) {
723 Section & s = g_options.pull_section("global");692 // if this is an internet game, tell the metaserver that client is back in the lobby.
724 m_password = s.get_string("dedicated_password", "");693 if (m_internet)
725694 InternetGaming::ref().set_game_done();
726 // And we read the message of the day695 return;
727 const std::string dedicated_motd_key =
728 (boost::format
729 (_("This is a dedicated server. Send \"@%s help\" to get a full list of available commands."))
730 % d->localplayername).str();
731 m_dedicated_motd = s.get_string("dedicated_motd", dedicated_motd_key.c_str());
732
733 // Maybe this is the first run, so we try to setup the DedicatedLog
734 // empty strings are treated as "do not write this type of log"
735 DedicatedLog * dl = DedicatedLog::get();
736 bool needip = false;
737 if (!dl->set_log_file_path (s.get_string("dedicated_log_file_path", "")))
738 dedicatedlog("Warning: Could not set dedicated log file path");
739 if (!dl->set_chat_file_path(s.get_string("dedicated_chat_file_path", "")))
740 dedicatedlog("Warning: Could not set dedicated chat file path");
741 if (!dl->write_info_active()) {
742 if (!dl->set_info_file_path(s.get_string("dedicated_info_file_path", "")))
743 dedicatedlog("Warning: Could not set dedicated info file path");
744 else {
745 needip = true;
746 dl->set_server_data(InternetGaming::ref().get_local_servername(), m_dedicated_motd);
747 }
748 }
749
750 dl->chat_add_spacer();
751 // Setup by the users
752 log ("[Dedicated] Entering set up mode, waiting for user interaction!\n");
753
754 while (!d->dedicated_start) {
755 handle_network();
756 // TODO(unknown): this should be improved.
757#ifndef _WIN32
758 if (d->clients.empty()) {
759 if (usleep(100000)) // Sleep for 0.1 seconds - there is not anybody connected anyways.
760 return;
761 if (needip && (InternetGaming::ref().ip().size() < 1)) {
762 dl->set_server_ip(InternetGaming::ref().ip());
763 needip = false;
764 }
765 } else {
766 if (usleep(200) == -1)
767 return;
768 }
769#else
770 if (d->clients.empty())
771 Sleep(100);
772 else
773 Sleep(1);
774#endif
775 }
776 d->dedicated_start = false;
777 } else {
778 FullscreenMenuLaunchMPG lm(&d->hp, this);
779 lm.set_chat_provider(d->chat);
780 const FullscreenMenuBase::MenuTarget code = lm.run<FullscreenMenuBase::MenuTarget>();
781 if (code == FullscreenMenuBase::MenuTarget::kBack) {
782 // if this is an internet game, tell the metaserver that client is back in the lobby.
783 if (m_internet)
784 InternetGaming::ref().set_game_done();
785 return;
786 }
787 }696 }
788697
789 // if this is an internet game, tell the metaserver that the game started698 // if this is an internet game, tell the metaserver that the game started
@@ -805,61 +714,41 @@
805#endif714#endif
806715
807 try {716 try {
808 // NOTE loader_ui will stay uninitialized, if this is run as dedicated, so all called functions need
809 // NOTE to check whether the pointer is valid.
810 std::unique_ptr<UI::ProgressWindow> loader_ui;717 std::unique_ptr<UI::ProgressWindow> loader_ui;
811 GameTips * tips = nullptr;718 GameTips * tips = nullptr;
812 if (m_is_dedicated) {719 loader_ui.reset(new UI::ProgressWindow("images/loadscreens/progress.png"));
813 log ("[Dedicated] Starting the game...\n");720 std::vector<std::string> tipstext;
814 d->game = &game;721 tipstext.push_back("general_game");
815 game.set_game_controller(this);722 tipstext.push_back("multiplayer");
816723 try {
817 if (d->settings.savegame) {724 tipstext.push_back(d->hp.get_players_tribe());
818 // Read and broadcast original win condition725 } catch (GameSettingsProvider::NoTribe) {
819 Widelands::GameLoader gl(d->settings.mapfilename, game);726 }
820 Widelands::GamePreloadPacket gpdp;727 tips = new GameTips(*loader_ui, tipstext);
821 gl.preload_game(gpdp);728
822729 loader_ui->step(_("Preparing game"));
823 set_win_condition_script(gpdp.get_win_condition());730
824 }731 d->game = &game;
732 game.set_game_controller(this);
733 InteractiveGameBase* igb;
734 uint8_t pn = d->settings.playernum + 1;
735
736 if (d->settings.savegame) {
737 // Read and broadcast original win condition
738 Widelands::GameLoader gl(d->settings.mapfilename, game);
739 Widelands::GamePreloadPacket gpdp;
740 gl.preload_game(gpdp);
741
742 set_win_condition_script(gpdp.get_win_condition());
743 }
744
745 if ((pn > 0) && (pn <= UserSettings::highest_playernum())) {
746 igb = new InteractivePlayer(game, g_options.pull_section("global"), pn, true);
825 } else {747 } else {
826 loader_ui.reset(new UI::ProgressWindow ("images/loadscreens/progress.png"));748 igb = new InteractiveSpectator(game, g_options.pull_section("global"), true);
827 std::vector<std::string> tipstext;
828 tipstext.push_back("general_game");
829 tipstext.push_back("multiplayer");
830 try {
831 tipstext.push_back(d->hp.get_players_tribe());
832 } catch (GameSettingsProvider::NoTribe) {}
833 tips = new GameTips(*loader_ui, tipstext);
834
835 loader_ui->step(_("Preparing game"));
836
837 d->game = &game;
838 game.set_game_controller(this);
839 InteractiveGameBase * igb;
840 uint8_t pn = d->settings.playernum + 1;
841
842 if (d->settings.savegame) {
843 // Read and broadcast original win condition
844 Widelands::GameLoader gl(d->settings.mapfilename, game);
845 Widelands::GamePreloadPacket gpdp;
846 gl.preload_game(gpdp);
847
848 set_win_condition_script(gpdp.get_win_condition());
849 }
850
851 if ((pn > 0) && (pn <= UserSettings::highest_playernum())) {
852 igb =
853 new InteractivePlayer
854 (game, g_options.pull_section("global"),
855 pn, true);
856 } else
857 igb =
858 new InteractiveSpectator
859 (game, g_options.pull_section("global"), true);
860 igb->set_chat_provider(d->chat);
861 game.set_ibase(igb);
862 }749 }
750 igb->set_chat_provider(d->chat);
751 game.set_ibase(igb);
863752
864 if (!d->settings.savegame) // new game753 if (!d->settings.savegame) // new game
865 game.init_newgame (loader_ui.get(), d->settings);754 game.init_newgame (loader_ui.get(), d->settings);
@@ -879,39 +768,18 @@
879 // wait mode when there are no clients768 // wait mode when there are no clients
880 check_hung_clients();769 check_hung_clients();
881 init_computer_players();770 init_computer_players();
882 if (m_is_dedicated) {
883 // Statistics: new game started
884 std::vector<std::string> clients;
885 for (uint32_t i = 0; i < d->settings.users.size(); ++i)
886 if (d->settings.users.at(i).position != UserSettings::not_connected())
887 if (d->settings.users.at(i).name != d->localplayername) // all names, but the dedicated server
888 clients.push_back(d->settings.users.at(i).name);
889 DedicatedLog::get()->game_start(clients, game.map().get_name().c_str());
890 }
891 game.run771 game.run
892 (loader_ui.get(),772 (loader_ui.get(),
893 d->settings.savegame ? Widelands::Game::Loaded : d->settings.scenario ?773 d->settings.savegame ? Widelands::Game::Loaded : d->settings.scenario ?
894 Widelands::Game::NewMPScenario : Widelands::Game::NewNonScenario,774 Widelands::Game::NewMPScenario : Widelands::Game::NewNonScenario,
895 "",775 "",
896 false);776 false, "nethost");
897777
898 delete tips;778 delete tips;
899779
900 // if this is an internet game, tell the metaserver that the game is done.780 // if this is an internet game, tell the metaserver that the game is done.
901 if (m_internet)781 if (m_internet)
902 InternetGaming::ref().set_game_done();782 InternetGaming::ref().set_game_done();
903
904 if (m_is_dedicated) {
905 // Statistics: game ended
906 std::vector<std::string> winners;
907 for (uint32_t i = 0; i < d->settings.users.size(); ++i)
908 // We do *not* only check connected users but all, as normally the players are already
909 // disconnected once the server reaches this line of code.
910 if (d->settings.users.at(i).name != d->localplayername) // all names, but the dedicated server
911 if (d->settings.users.at(i).result == Widelands::PlayerEndResult::PLAYER_WON)
912 winners.push_back(d->settings.users.at(i).name);
913 DedicatedLog::get()->game_end(winners);
914 }
915 clear_computer_players();783 clear_computer_players();
916 } catch (...) {784 } catch (...) {
917 WLApplication::emergency_save(game);785 WLApplication::emergency_save(game);
@@ -963,11 +831,6 @@
963831
964 for (uint32_t i = 0; i < d->computerplayers.size(); ++i)832 for (uint32_t i = 0; i < d->computerplayers.size(); ++i)
965 d->computerplayers.at(i)->think();833 d->computerplayers.at(i)->think();
966 } else if (m_is_dedicated) {
967 // Take care that every player gets updated during set up time
968 for (uint8_t i = 0; i < d->settings.players.size(); ++i) {
969 d->npsb.refresh(i);
970 }
971 }834 }
972}835}
973836
@@ -997,9 +860,6 @@
997 if (msg.msg.empty())860 if (msg.msg.empty())
998 return;861 return;
999862
1000 if (is_dedicated())
1001 DedicatedLog::get()->chat(msg);
1002
1003 if (msg.recipient.empty()) {863 if (msg.recipient.empty()) {
1004 SendPacket s;864 SendPacket s;
1005 s.unsigned_8(NETCMD_CHAT);865 s.unsigned_8(NETCMD_CHAT);
@@ -1016,9 +876,6 @@
1016876
1017 // Is this a pm for the host player?877 // Is this a pm for the host player?
1018 if (d->localplayername == msg.recipient) {878 if (d->localplayername == msg.recipient) {
1019 // If this is a dedicated server, handle commands
1020 if (m_is_dedicated)
1021 handle_dserver_command(msg.msg, msg.sender);
1022 d->chat.receive(msg);879 d->chat.receive(msg);
1023 // Write the SendPacket - will be used below to show that the message880 // Write the SendPacket - will be used below to show that the message
1024 // was received.881 // was received.
@@ -1036,7 +893,7 @@
1036 s.unsigned_8(1);893 s.unsigned_8(1);
1037 s.string(msg.recipient);894 s.string(msg.recipient);
1038 s.send(d->clients.at(clientnum).sock);895 s.send(d->clients.at(clientnum).sock);
1039 dedicatedlog("[Host]: personal chat: from %s to %s\n", msg.sender.c_str(), msg.recipient.c_str());896 log("[Host]: personal chat: from %s to %s\n", msg.sender.c_str(), msg.recipient.c_str());
1040 } else {897 } else {
1041 std::string fail = "Failed to send message: Recipient \"";898 std::string fail = "Failed to send message: Recipient \"";
1042 fail += msg.recipient + "\" could not be found!";899 fail += msg.recipient + "\" could not be found!";
@@ -1068,8 +925,6 @@
1068 else if (d->localplayername == msg.sender)925 else if (d->localplayername == msg.sender)
1069 d->chat.receive(msg);926 d->chat.receive(msg);
1070 else { // host is not the sender -> get sender927 else { // host is not the sender -> get sender
1071 if (d->localplayername == msg.recipient && m_is_dedicated)
1072 return; // There will be an immediate answer from the host
1073 uint16_t i = 0;928 uint16_t i = 0;
1074 for (; i < d->settings.users.size(); ++i) {929 for (; i < d->settings.users.size(); ++i) {
1075 const UserSettings & user = d->settings.users.at(i);930 const UserSettings & user = d->settings.users.at(i);
@@ -1085,10 +940,10 @@
1085 s.send(d->clients.at(j).sock);940 s.send(d->clients.at(j).sock);
1086 else941 else
1087 // Better no wexception it would break the whole game942 // Better no wexception it would break the whole game
1088 dedicatedlog("WARNING: user was found but no client is connected to it!\n");943 log("WARNING: user was found but no client is connected to it!\n");
1089 } else944 } else
1090 // Better no wexception it would break the whole game945 // Better no wexception it would break the whole game
1091 dedicatedlog("WARNING: sender could not be found!");946 log("WARNING: sender could not be found!");
1092 }947 }
1093 }948 }
1094}949}
@@ -1164,217 +1019,6 @@
1164 arg2 = "";1019 arg2 = "";
1165}1020}
11661021
1167
1168/**
1169 * This function is used to handle commands for the dedicated server
1170 */
1171void NetHost::handle_dserver_command(std::string cmdarray, std::string sender)
1172{
1173 assert(m_is_dedicated);
1174
1175 ChatMessage c;
1176 c.time = time(nullptr);
1177 c.playern = -2;
1178 c.sender = d->localplayername;
1179 c.recipient = sender;
1180
1181 // Find the client that send the chat message
1182 int32_t num = check_client(sender);
1183 if (num < 0) // host or not found
1184 return;
1185 Client & client = d->clients[num];
1186
1187 if (cmdarray.size() < 1) {
1188 return;
1189 }
1190
1191 // Split up in "cmd" "arg1" "arg2"
1192 std::string cmd, arg1, arg2;
1193 split_command_array(cmdarray, cmd, arg1, arg2);
1194
1195 // help
1196 if (cmd == "help") {
1197 if (d->game)
1198 c.msg =
1199 (boost::format("<br>%s<br>%s<br>%s<br>%s")
1200 % _("Available host commands are:")
1201 /** TRANSLATORS: Available host command */
1202 % _("/help - Shows this help")
1203 /** TRANSLATORS: Available host command */
1204 % _("host $ - Tries to run the host command $")
1205 /** TRANSLATORS: Available host command */
1206 % _("save $ - Saves the current game state as $.wgf")
1207 ).str();
1208 else
1209 c.msg =
1210 (boost::format("<br>%s<br>%s<br>%s")
1211 % _("Available host commands are:")
1212 /** TRANSLATORS: Available host command */
1213 % _("/help - Shows this help")
1214 /** TRANSLATORS: Available host command */
1215 % _("host $ - Tries to run the host command $")
1216 ).str();
1217 if (m_password.size() > 1) {
1218 c.msg += "<br>";
1219 c.msg += _("pwd $ - Sends the password $ to the host");
1220 }
1221 send(c);
1222
1223 // host
1224 } else if (cmd == "host") {
1225 if (!client.dedicated_access) {
1226 c.msg = _("Access to host commands denied. To gain access, send the password with pwd command.");
1227 send(c);
1228 return;
1229 }
1230 std::string temp = arg1 + " " + arg2;
1231 c.msg = (boost::format(_("%1$s told me to run the command: \"%2$s\"")) % sender % temp).str();
1232 c.recipient = "";
1233 send(c);
1234 d->chat.send(temp);
1235
1236 } else if (cmd == "save") {
1237 // Check whether saving is allowed at all
1238 Section & s = g_options.pull_section("global");
1239 if (!s.get_bool("dedicated_saving", true)) {
1240 c.msg = _("Sorry! Saving was deactivated on this dedicated server!");
1241 send(c);
1242 } else if (!d->game) {
1243 c.msg = _("Cannot save while there is no game running!");
1244 send(c);
1245 } else {
1246 //try to save the game
1247 std::string savename = "save/" + arg1;
1248 if (!arg2.empty()) { // only add space and arg2, if arg2 has anything to print.
1249 savename += " " + arg2;
1250 }
1251 savename += ".wgf";
1252 std::string * error = new std::string();
1253 SaveHandler & sh = d->game->save_handler();
1254 if (sh.save_game(*d->game, savename, error))
1255 c.msg = _("Game successfully saved!");
1256 else
1257 c.msg =
1258 (boost::format(_("Could not save the game to the file \"%1$s\"! (%2$s)"))
1259 % savename % error)
1260 .str();
1261 send(c);
1262 delete error;
1263 }
1264
1265 } else if (cmd == "pwd") {
1266 if (m_password.empty()) {
1267 c.msg = _("This server is not password protected!");
1268 send(c);
1269 } else if (arg1 != m_password) {
1270 c.msg = _("The sent password was incorrect!");
1271 send(c);
1272 } else {
1273 // Once the client gained access (s)he might need the knowledge about available maps and saved games
1274 dserver_send_maps_and_saves(client);
1275
1276 // Send the client the access granted message
1277 SendPacket s;
1278 s.reset();
1279 s.unsigned_8(NETCMD_DEDICATED_ACCESS);
1280 s.send(client.sock);
1281 client.dedicated_access = true;
1282
1283 c.msg = _("The password was correct, access was granted!");
1284 send(c);
1285 }
1286
1287 // default
1288 } else {
1289 c.msg = (boost::format(_("Unknown dedicated server command \"%s\"!")) % cmd).str();
1290 send(c);
1291 }
1292}
1293
1294void NetHost::dserver_send_maps_and_saves(Client & client) {
1295 assert (!d->game);
1296
1297 if (d->settings.maps.empty()) {
1298 // Read in maps
1299 std::vector<std::string> directories;
1300 directories.push_back("maps");
1301 while (!directories.empty()) {
1302 FilenameSet files = g_fs->list_directory(directories.at(directories.size() - 1).c_str());
1303 directories.resize(directories.size() - 1);
1304 Widelands::Map map;
1305 for (const std::string& filename : files) {
1306 std::unique_ptr<Widelands::MapLoader> ml = map.get_correct_loader(filename);
1307 if (ml) {
1308 map.set_filename(filename);
1309 ml->preload_map(true);
1310 DedicatedMapInfos info;
1311 info.path = filename;
1312 info.players = map.get_nrplayers();
1313 info.scenario = map.scenario_types() & Widelands::Map::MP_SCENARIO;
1314 d->settings.maps.push_back(info);
1315 } else {
1316 if
1317 (g_fs->is_directory(filename)
1318 &&
1319 strcmp(FileSystem::fs_filename(filename.c_str()), ".")
1320 &&
1321 strcmp(FileSystem::fs_filename(filename.c_str()), ".."))
1322 {
1323 directories.push_back(filename);
1324 }
1325 }
1326 }
1327 }
1328 }
1329
1330 if (d->settings.saved_games.empty()) {
1331 // Read in saved games
1332 FilenameSet files = g_fs->list_directory("save");
1333 Widelands::Game game;
1334 Widelands::GamePreloadPacket gpdp;
1335 const FilenameSet & gamefiles = files;
1336 for (const std::string& temp_filenames : gamefiles) {
1337 char const * const name = temp_filenames.c_str();
1338 try {
1339 Widelands::GameLoader gl(name, game);
1340 gl.preload_game(gpdp);
1341
1342 // If we are here, the saved game is valid
1343 std::unique_ptr<FileSystem> sg_fs(g_fs->make_sub_file_system(name));
1344 Profile prof;
1345 prof.read("map/elemental", nullptr, *sg_fs);
1346 Section & s = prof.get_safe_section("global");
1347
1348 DedicatedMapInfos info;
1349 info.path = name;
1350 info.players = static_cast<uint8_t>(s.get_safe_int("nr_players"));
1351 d->settings.saved_games.push_back(info);
1352 } catch (const WException &) {}
1353 }
1354 }
1355
1356 SendPacket s;
1357
1358 // Send list of maps
1359 for (uint8_t i = 0; i < d->settings.maps.size(); ++i) {
1360 s.reset();
1361 s.unsigned_8(NETCMD_DEDICATED_MAPS);
1362 s.string (d->settings.maps[i].path);
1363 s.unsigned_8(d->settings.maps[i].players);
1364 s.unsigned_8(d->settings.maps[i].scenario ? 1 : 0);
1365 s.send(client.sock);
1366 }
1367
1368 // Send list of saved games
1369 for (uint8_t i = 0; i < d->settings.saved_games.size(); ++i) {
1370 s.reset();
1371 s.unsigned_8(NETCMD_DEDICATED_SAVED_GAMES);
1372 s.string (d->settings.saved_games[i].path);
1373 s.unsigned_8(d->settings.saved_games[i].players);
1374 s.send(client.sock);
1375 }
1376}
1377
1378void NetHost::send_system_message_code1022void NetHost::send_system_message_code
1379 (const std::string & code, const std::string & a, const std::string & b, const std::string & c)1023 (const std::string & code, const std::string & a, const std::string & b, const std::string & c)
1380{1024{
@@ -1394,8 +1038,6 @@
1394 msg.playern = UserSettings::none(); // == System message1038 msg.playern = UserSettings::none(); // == System message
1395 // c.sender remains empty to indicate a system message1039 // c.sender remains empty to indicate a system message
1396 d->chat.receive(msg);1040 d->chat.receive(msg);
1397 if (m_is_dedicated)
1398 DedicatedLog::get()->chat(msg);
1399}1041}
14001042
1401int32_t NetHost::get_frametime()1043int32_t NetHost::get_frametime()
@@ -1962,7 +1604,7 @@
1962bool NetHost::write_map_transfer_info(SendPacket & s, std::string mapfilename) {1604bool NetHost::write_map_transfer_info(SendPacket & s, std::string mapfilename) {
1963 // TODO(unknown): not yet able to handle directory type maps / savegames1605 // TODO(unknown): not yet able to handle directory type maps / savegames
1964 if (g_fs->is_directory(mapfilename)) {1606 if (g_fs->is_directory(mapfilename)) {
1965 dedicatedlog("Map/Save is a directory! No way for making it available a.t.m.!\n");1607 log("Map/Save is a directory! No way for making it available a.t.m.!\n");
1966 return false;1608 return false;
1967 }1609 }
19681610
@@ -2027,13 +1669,8 @@
2027 assert(client.playernum == UserSettings::not_connected());1669 assert(client.playernum == UserSettings::not_connected());
2028 assert(client.sock);1670 assert(client.sock);
20291671
2030 // Just for statistics
2031 DedicatedLog::get()->client_login();
2032
2033 // The client gets its own initial data set.1672 // The client gets its own initial data set.
2034 client.playernum = UserSettings::none();1673 client.playernum = UserSettings::none();
2035 // only used at password protected dedicated server, but better initialize always
2036 client.dedicated_access = m_is_dedicated ? (m_password.empty()) : false;
20371674
2038 if (!d->game) // just in case we allow connection of spectators/players after game start1675 if (!d->game) // just in case we allow connection of spectators/players after game start
2039 for (uint32_t i = 0; i < d->settings.users.size(); ++i)1676 for (uint32_t i = 0; i < d->settings.users.size(); ++i)
@@ -2066,7 +1703,7 @@
2066 d->settings.users.at(client.usernum).name = effective_name;1703 d->settings.users.at(client.usernum).name = effective_name;
2067 d->settings.users.at(client.usernum).position = UserSettings::none();1704 d->settings.users.at(client.usernum).position = UserSettings::none();
20681705
2069 dedicatedlog("[Host]: Client %u: welcome to usernum %u\n", number, client.usernum);1706 log("[Host]: Client %u: welcome to usernum %u\n", number, client.usernum);
20701707
2071 SendPacket s;1708 SendPacket s;
2072 s.unsigned_8(NETCMD_HELLO);1709 s.unsigned_8(NETCMD_HELLO);
@@ -2135,34 +1772,6 @@
2135 }1772 }
21361773
2137 send_system_message_code("CLIENT_HAS_JOINED_GAME", effective_name);1774 send_system_message_code("CLIENT_HAS_JOINED_GAME", effective_name);
2138
2139 // If this is a dedicated server, inform the player
2140 if (m_is_dedicated) {
2141 ChatMessage c;
2142 c.time = time(nullptr);
2143 c.playern = -2;
2144 c.sender = d->localplayername;
2145 // Send the message of the day if exists
2146 c.msg = "<br>" + m_dedicated_motd;
2147 if (m_password.size() > 1) {
2148 c.msg += "<br>";
2149 c.msg +=
2150 (boost::format
2151 (_("This server is password protected. You can send the password with: \"@%s pwd PASSWORD\""))
2152 % d->localplayername)
2153 .str();
2154 } else {
2155 // Once the client gained access it might need the knowledge about available maps and saved games
2156 dserver_send_maps_and_saves(client);
2157
2158 // If not password protected, give the client access to the settings
2159 s.reset();
2160 s.unsigned_8(NETCMD_DEDICATED_ACCESS);
2161 s.send(client.sock);
2162 }
2163 c.recipient = d->settings.users.at(client.usernum).name;
2164 send(c);
2165 }
2166}1775}
21671776
2168void NetHost::committed_network_time(int32_t const time)1777void NetHost::committed_network_time(int32_t const time)
@@ -2194,7 +1803,7 @@
2194 }1803 }
21951804
2196 client.time = time;1805 client.time = time;
2197 dedicatedlog("[Host]: Client %i: Time %i\n", number, time);1806 log("[Host]: Client %i: Time %i\n", number, time);
21981807
2199 if (d->waiting) {1808 if (d->waiting) {
2200 log1809 log
@@ -2253,29 +1862,6 @@
2253 d->settings.users.at(d->clients.at(i).usernum).name,1862 d->settings.users.at(d->clients.at(i).usernum).name,
2254 seconds.c_str());1863 seconds.c_str());
2255 d->clients.at(i).lastdelta = deltanow;1864 d->clients.at(i).lastdelta = deltanow;
2256 if (m_is_dedicated) {
2257 seconds = (boost::format("%li") % (300 - deltanow)).str();
2258 send_system_message_code
2259 ("CLIENT_HUNG_AUTOKICK",
2260 d->settings.users.at(d->clients.at(i).usernum).name,
2261 seconds.c_str());
2262 }
2263 }
2264
2265 // If this is a dedicated server, there is no host that cares about kicking hung players
2266 // This is especially problematic, if the last or all players hung and the dedicated
2267 // server does not automatically restart.
2268 // 5 minutes for all other players to react before the dedicated server takes care
2269 // about the situation itself
2270 if ((d->clients.at(i).hung_since < (time(nullptr) - 300)) && m_is_dedicated) {
2271 disconnect_client(i, "CLIENT_TIMEOUTED");
2272 // Try to save the game
2273 std::string savename = (boost::format("save/client_hung_%i.wmf") % time(nullptr)).str();
2274 std::string * error = new std::string();
2275 SaveHandler & sh = d->game->save_handler();
2276 if (sh.save_game(*d->game, savename, error))
2277 send_system_message_code("GAME_SAVED_AS", savename);
2278 delete error;
2279 }1865 }
2280 }1866 }
2281 }1867 }
@@ -2284,7 +1870,7 @@
22841870
2285 if (!d->waiting) {1871 if (!d->waiting) {
2286 if (nrhung) {1872 if (nrhung) {
2287 dedicatedlog("[Host]: %i clients hung. Entering wait mode\n", nrhung);1873 log("[Host]: %i clients hung. Entering wait mode\n", nrhung);
22881874
2289 // Brake and wait1875 // Brake and wait
2290 d->waiting = true;1876 d->waiting = true;
@@ -2347,14 +1933,12 @@
2347 // No pause was forced - normal speed calculation1933 // No pause was forced - normal speed calculation
2348 std::vector<uint32_t> speeds;1934 std::vector<uint32_t> speeds;
23491935
2350 if (!m_is_dedicated)1936 speeds.push_back(d->localdesiredspeed);
2351 speeds.push_back(d->localdesiredspeed);
2352 for (uint32_t i = 0; i < d->clients.size(); ++i) {1937 for (uint32_t i = 0; i < d->clients.size(); ++i) {
2353 if (d->clients.at(i).playernum <= UserSettings::highest_playernum())1938 if (d->clients.at(i).playernum <= UserSettings::highest_playernum())
2354 speeds.push_back(d->clients.at(i).desiredspeed);1939 speeds.push_back(d->clients.at(i).desiredspeed);
2355 }1940 }
2356 if (speeds.empty()) // Possible in dedicated server games with only spectators1941 assert(!speeds.empty());
2357 return;
23581942
2359 std::sort(speeds.begin(), speeds.end());1943 std::sort(speeds.begin(), speeds.end());
23601944
@@ -2395,7 +1979,7 @@
2395 for (uint32_t i = 0; i < d->clients.size(); ++i)1979 for (uint32_t i = 0; i < d->clients.size(); ++i)
2396 d->clients.at(i).syncreport_arrived = false;1980 d->clients.at(i).syncreport_arrived = false;
23971981
2398 dedicatedlog("[Host]: Requesting sync reports for time %i\n", d->syncreport_time);1982 log("[Host]: Requesting sync reports for time %i\n", d->syncreport_time);
23991983
2400 SendPacket s;1984 SendPacket s;
2401 s.unsigned_8(NETCMD_SYNCREQUEST);1985 s.unsigned_8(NETCMD_SYNCREQUEST);
@@ -2425,7 +2009,7 @@
2425 }2009 }
24262010
2427 d->syncreport_pending = false;2011 d->syncreport_pending = false;
2428 dedicatedlog("[Host]: comparing syncreports for time %i\n", d->syncreport_time);2012 log("[Host]: comparing syncreports for time %i\n", d->syncreport_time);
24292013
2430 for (uint32_t i = 0; i < d->clients.size(); ++i) {2014 for (uint32_t i = 0; i < d->clients.size(); ++i) {
2431 Client & client = d->clients.at(i);2015 Client & client = d->clients.at(i);
@@ -2474,7 +2058,7 @@
24742058
2475 // Check for new connections.2059 // Check for new connections.
2476 while (d->svsock != nullptr && (sock = SDLNet_TCP_Accept(d->svsock)) != nullptr) {2060 while (d->svsock != nullptr && (sock = SDLNet_TCP_Accept(d->svsock)) != nullptr) {
2477 dedicatedlog("[Host]: Received a connection request\n");2061 log("[Host]: Received a connection request\n");
24782062
2479 SDLNet_TCP_AddSocket (d->sockset, sock);2063 SDLNet_TCP_AddSocket (d->sockset, sock);
24802064
@@ -2571,7 +2155,7 @@
25712155
2572 if (client.playernum == UserSettings::not_connected()) {2156 if (client.playernum == UserSettings::not_connected()) {
2573 if (cmd == NETCMD_METASERVER_PING) {2157 if (cmd == NETCMD_METASERVER_PING) {
2574 dedicatedlog("[Host]: Received ping from metaserver.\n");2158 log("[Host]: Received ping from metaserver.\n");
2575 // Send PING back2159 // Send PING back
2576 SendPacket s;2160 SendPacket s;
2577 s.unsigned_8(NETCMD_METASERVER_PING);2161 s.unsigned_8(NETCMD_METASERVER_PING);
@@ -2606,56 +2190,12 @@
26062190
2607 switch (cmd) {2191 switch (cmd) {
2608 case NETCMD_PONG:2192 case NETCMD_PONG:
2609 dedicatedlog("[Host]: Client %u: got pong\n", i);2193 log("[Host]: Client %u: got pong\n", i);
2610 break;2194 break;
26112195
2612 case NETCMD_SETTING_MAP:2196 case NETCMD_SETTING_MAP:
2613 if (!d->game) {2197 if (!d->game) {
2614 // Only valid if the server is dedicated and the client was granted access2198 throw DisconnectException("NO_ACCESS_TO_SERVER");
2615 if (!client.dedicated_access)
2616 throw DisconnectException("NO_ACCESS_TO_SERVER");
2617
2618 // We want to skip past the name, so read that but don't do anything with it
2619 r.string();
2620 std::string path = g_fs->FileSystem::fix_cross_file(r.string());
2621 bool savegame = r.unsigned_8() == 1;
2622 bool scenario = r.unsigned_8() == 1;
2623 if (savegame) {
2624 if (g_fs->file_exists(path)) {
2625 // Check if file is a saved game and if yes read out the needed data
2626 try {
2627 Widelands::Game game;
2628 Widelands::GamePreloadPacket gpdp;
2629 Widelands::GameLoader gl(path, game);
2630 gl.preload_game(gpdp);
2631
2632 // If we are here, it is a saved game file :)
2633 // Read the needed data from file "elemental" of the used map.
2634 std::unique_ptr<FileSystem> sg_fs(g_fs->make_sub_file_system(path.c_str()));
2635 Profile prof;
2636 prof.read("map/elemental", nullptr, *sg_fs);
2637 Section & s = prof.get_safe_section("global");
2638 uint8_t nr_players = s.get_safe_int("nr_players");
2639
2640 d->settings.scenario = false;
2641 d->hp.set_map(gpdp.get_mapname(), path, nr_players, true);
2642 } catch (const WException &) {}
2643 }
2644 } else {
2645 if (g_fs->file_exists(path)) {
2646 // Check if file is a map and if yes read out the needed data
2647 Widelands::Map map;
2648 i18n::Textdomain td("maps");
2649 std::unique_ptr<Widelands::MapLoader> ml = map.get_correct_loader(path);
2650 if (ml != nullptr) {
2651 // Yes it is a map file :)
2652 map.set_filename(path);
2653 ml->preload_map(true);
2654 d->settings.scenario = scenario;
2655 d->hp.set_map(map.get_name(), path, map.get_nrplayers(), false);
2656 }
2657 }
2658 }
2659 }2199 }
2660 break;2200 break;
26612201
@@ -2665,9 +2205,7 @@
2665 if (!d->game) {2205 if (!d->game) {
2666 uint8_t num = r.unsigned_8();2206 uint8_t num = r.unsigned_8();
2667 if (num != client.playernum)2207 if (num != client.playernum)
2668 // Only valid if the server is dedicated and the client was granted access2208 throw DisconnectException("NO_ACCESS_TO_PLAYER");
2669 if (!client.dedicated_access)
2670 throw DisconnectException("NO_ACCESS_TO_PLAYER");
2671 std::string tribe = r.string();2209 std::string tribe = r.string();
2672 bool random_tribe = r.unsigned_8() == 1;2210 bool random_tribe = r.unsigned_8() == 1;
2673 set_player_tribe(num, tribe, random_tribe);2211 set_player_tribe(num, tribe, random_tribe);
@@ -2680,9 +2218,7 @@
2680 if (!d->game) {2218 if (!d->game) {
2681 uint8_t num = r.unsigned_8();2219 uint8_t num = r.unsigned_8();
2682 if (num != client.playernum)2220 if (num != client.playernum)
2683 // Only valid if the server is dedicated and the client was granted access2221 throw DisconnectException("NO_ACCESS_TO_PLAYER");
2684 if (!client.dedicated_access)
2685 throw DisconnectException("NO_ACCESS_TO_PLAYER");
2686 set_player_shared(num, r.unsigned_8());2222 set_player_shared(num, r.unsigned_8());
2687 }2223 }
2688 break;2224 break;
@@ -2691,9 +2227,7 @@
2691 if (!d->game) {2227 if (!d->game) {
2692 uint8_t num = r.unsigned_8();2228 uint8_t num = r.unsigned_8();
2693 if (num != client.playernum)2229 if (num != client.playernum)
2694 // Only valid if the server is dedicated and the client was granted access2230 throw DisconnectException("NO_ACCESS_TO_PLAYER");
2695 if (!client.dedicated_access)
2696 throw DisconnectException("NO_ACCESS_TO_PLAYER");
2697 set_player_team(num, r.unsigned_8());2231 set_player_team(num, r.unsigned_8());
2698 }2232 }
2699 break;2233 break;
@@ -2702,9 +2236,7 @@
2702 if (!d->game) {2236 if (!d->game) {
2703 uint8_t num = r.unsigned_8();2237 uint8_t num = r.unsigned_8();
2704 if (num != client.playernum)2238 if (num != client.playernum)
2705 // Only valid if the server is dedicated and the client was granted access2239 throw DisconnectException("NO_ACCESS_TO_PLAYER");
2706 if (!client.dedicated_access)
2707 throw DisconnectException("NO_ACCESS_TO_PLAYER");
2708 d->npsb.toggle_init(num);2240 d->npsb.toggle_init(num);
2709 }2241 }
2710 break;2242 break;
@@ -2718,30 +2250,19 @@
27182250
2719 case NETCMD_SETTING_PLAYER:2251 case NETCMD_SETTING_PLAYER:
2720 if (!d->game) {2252 if (!d->game) {
2721 // Only valid if the server is dedicated and the client was granted access2253 throw DisconnectException("NO_ACCESS_TO_SERVER");
2722 if (!client.dedicated_access)
2723 throw DisconnectException("NO_ACCESS_TO_SERVER");
2724 d->hp.next_player_state(r.unsigned_8());
2725 }2254 }
2726 break;2255 break;
27272256
2728 case NETCMD_WIN_CONDITION:2257 case NETCMD_WIN_CONDITION:
2729 if (!d->game) {2258 if (!d->game) {
2730 // Only valid if the server is dedicated and the client was granted access2259 throw DisconnectException("NO_ACCESS_TO_SERVER");
2731 if (!client.dedicated_access)
2732 throw DisconnectException("NO_ACCESS_TO_SERVER");
2733 d->hp.next_win_condition();
2734 }2260 }
2735 break;2261 break;
27362262
2737 case NETCMD_LAUNCH:2263 case NETCMD_LAUNCH:
2738 if (!d->game) {2264 if (!d->game) {
2739 // Only valid if the server is dedicated and the client was granted access2265 throw DisconnectException("NO_ACCESS_TO_SERVER");
2740 if (!client.dedicated_access)
2741 throw DisconnectException("NO_ACCESS_TO_SERVER");
2742 if (!can_launch())
2743 throw DisconnectException("START_SENT_NOT_READY");
2744 d->dedicated_start = true;
2745 }2266 }
2746 break;2267 break;
27472268
@@ -2822,7 +2343,7 @@
2822 uint32_t part = r.unsigned_32();2343 uint32_t part = r.unsigned_32();
2823 std::string x = r.string();2344 std::string x = r.string();
2824 if (x != file->md5sum) {2345 if (x != file->md5sum) {
2825 dedicatedlog("[Host]: File transfer checksum missmatch %s != %s\n", x.c_str(), file->md5sum.c_str());2346 log("[Host]: File transfer checksum missmatch %s != %s\n", x.c_str(), file->md5sum.c_str());
2826 return; // Surely the file was changed, so we cancel here.2347 return; // Surely the file was changed, so we cancel here.
2827 }2348 }
2828 if (part >= file->parts.size())2349 if (part >= file->parts.size())
@@ -2871,7 +2392,7 @@
28712392
2872void NetHost::disconnect_player_controller(uint8_t const number, const std::string & name)2393void NetHost::disconnect_player_controller(uint8_t const number, const std::string & name)
2873{2394{
2874 dedicatedlog("[Host]: disconnect_player_controller(%u, %s)\n", number, name.c_str());2395 log("[Host]: disconnect_player_controller(%u, %s)\n", number, name.c_str());
28752396
2876 for (uint32_t i = 0; i < d->settings.users.size(); ++i) {2397 for (uint32_t i = 0; i < d->settings.users.size(); ++i) {
2877 if (d->settings.users.at(i).position == number) {2398 if (d->settings.users.at(i).position == number) {
@@ -2922,13 +2443,10 @@
2922 s.unsigned_32(client.usernum);2443 s.unsigned_32(client.usernum);
2923 write_setting_user(s, client.usernum);2444 write_setting_user(s, client.usernum);
2924 broadcast(s);2445 broadcast(s);
2925
2926 // Just for statistics
2927 DedicatedLog::get()->client_logout();
2928 } else2446 } else
2929 send_system_message_code("UNKNOWN_LEFT_GAME", reason, arg);2447 send_system_message_code("UNKNOWN_LEFT_GAME", reason, arg);
29302448
2931 dedicatedlog("[Host]: disconnect_client(%u, %s, %s)\n", number, reason.c_str(), arg.c_str());2449 log("[Host]: disconnect_client(%u, %s, %s)\n", number, reason.c_str(), arg.c_str());
29322450
2933 if (client.sock) {2451 if (client.sock) {
2934 if (sendreason) {2452 if (sendreason) {
@@ -2948,16 +2466,7 @@
29482466
2949 if (d->game) {2467 if (d->game) {
2950 check_hung_clients();2468 check_hung_clients();
2951 if (m_is_dedicated) {
2952 // Check whether there is at least one client connected. If not, stop the game.
2953 for (uint32_t i = 0; i < d->clients.size(); ++i)
2954 if (d->clients.at(i).playernum != UserSettings::not_connected())
2955 return;
2956 d->game->end_dedicated_game();
2957 dedicatedlog("[Dedicated] Stopping the running game...\n");
2958 }
2959 }2469 }
2960
2961}2470}
29622471
2963/**2472/**
@@ -3004,7 +2513,7 @@
3004 }2513 }
3005 }2514 }
30062515
3007 dedicatedlog2516 log
3008 ("NetHost::report_result(%d, %u, %s)\n",2517 ("NetHost::report_result(%d, %u, %s)\n",
3009 player->player_number(), static_cast<uint8_t>(result), info.c_str());2518 player->player_number(), static_cast<uint8_t>(result), info.c_str());
3010}2519}
30112520
=== modified file 'src/network/nethost.h'
--- src/network/nethost.h 2014-09-30 06:25:04 +0000
+++ src/network/nethost.h 2016-02-07 08:11:43 +0000
@@ -40,7 +40,7 @@
40 NetHost (const std::string & playername, bool internet = false);40 NetHost (const std::string & playername, bool internet = false);
41 virtual ~NetHost ();41 virtual ~NetHost ();
4242
43 void run(bool autostart = false);43 void run();
44 const std::string & get_local_playername() const;44 const std::string & get_local_playername() const;
45 int16_t get_local_playerposition();45 int16_t get_local_playerposition();
4646
@@ -90,8 +90,6 @@
90 void kick_user(uint32_t, std::string);90 void kick_user(uint32_t, std::string);
91 void split_command_array91 void split_command_array
92 (const std::string & cmdarray, std::string & cmd, std::string & arg1, std::string & arg2);92 (const std::string & cmdarray, std::string & cmd, std::string & arg1, std::string & arg2);
93 void handle_dserver_command(std::string, std::string);
94 void dserver_send_maps_and_saves(Client &);
9593
96 void report_result(uint8_t player, Widelands::PlayerEndResult result, const std::string & info) override;94 void report_result(uint8_t player, Widelands::PlayerEndResult result, const std::string & info) override;
9795
@@ -107,8 +105,6 @@
107105
108 bool forced_pause() {return m_forced_pause;}106 bool forced_pause() {return m_forced_pause;}
109107
110 bool is_dedicated() {return m_is_dedicated;}
111
112private:108private:
113 NetTransferFile * file;109 NetTransferFile * file;
114110
@@ -159,9 +155,6 @@
159155
160 NetHostImpl * d;156 NetHostImpl * d;
161 bool m_internet;157 bool m_internet;
162 bool m_is_dedicated;
163 std::string m_password;
164 std::string m_dedicated_motd;
165 bool m_forced_pause;158 bool m_forced_pause;
166};159};
167160
168161
=== modified file 'src/network/network_protocol.h'
--- src/network/network_protocol.h 2014-09-20 09:37:47 +0000
+++ src/network/network_protocol.h 2016-02-07 08:11:43 +0000
@@ -153,7 +153,6 @@
153153
154 /**154 /**
155 * During game setup, this command is sent by the host to advise clients of a map change.155 * During game setup, this command is sent by the host to advise clients of a map change.
156 * Or by a client on a dedicated server to advise a map change.
157 *156 *
158 * Payload is:157 * Payload is:
159 * \li string: human readable mapname158 * \li string: human readable mapname
@@ -183,8 +182,6 @@
183 * During game setup, this command updates the information associated to182 * During game setup, this command updates the information associated to
184 * one player slot.183 * one player slot.
185 *184 *
186 * The client sends this command to toggle the player type. This is only available if the server is
187 * dedicated and the client was granted access.
188 * Payload in that case is:185 * Payload in that case is:
189 * \li unsigned_8: number of the player186 * \li unsigned_8: number of the player
190 *187 *
@@ -216,7 +213,6 @@
216213
217 /**214 /**
218 * Sent by the host during game setup to indicate that the game starts.215 * Sent by the host during game setup to indicate that the game starts.
219 * Alternatively sent by the client to start a dedicated server.
220 *216 *
221 * The client must load the map and setup the game. As soon as the game217 * The client must load the map and setup the game. As soon as the game
222 * is fully loaded, it must behave as if a \ref NETCMD_WAIT command had218 * is fully loaded, it must behave as if a \ref NETCMD_WAIT command had
@@ -369,10 +365,9 @@
369 NETCMD_FILE_PART = 24,365 NETCMD_FILE_PART = 24,
370366
371 /**367 /**
372 * Sent by the host (or by the client if access was granted to dedicated server)368 * Sent by the host to change the win condition.
373 * to change the win condition.
374 *369 *
375 * If sent by the host, attached data is:370 * Attached data is:
376 * \li string: name of the win condition371 * \li string: name of the win condition
377 *372 *
378 * If sent by the client, no data is attached, as it is only a request to toggle373 * If sent by the client, no data is attached, as it is only a request to toggle
@@ -420,34 +415,11 @@
420 */415 */
421 NETCMD_SETTING_CHANGEINIT = 28,416 NETCMD_SETTING_CHANGEINIT = 28,
422417
423 /**418 // 29 - 31 were commands related to dedicated server. Do not use.
424 * This is sent by the server to grant access to the settings (as well as to acknowledge the correct419
425 * password if the server is password protected)420 /**
426 */421 * This is sent by the server to generate a clientsided translated system
427 NETCMD_DEDICATED_ACCESS = 29,422 * chat message. Payload is:
428
429 /**
430 * This is sent by the dedicated server to inform the client about the available maps on the dedicated
431 * server. Payload is:
432 *
433 * \li string: Path to the map file
434 * \li unsigned_8: Number of maximum players
435 * \li bool: Whether this map can be played as multiplayer scenario
436 */
437 NETCMD_DEDICATED_MAPS = 30,
438
439 /**
440 * This is sent by the dedicated server to inform the client about the available saved games on the
441 * dedicated server. Payload is:
442 *
443 * \li string: Path to the map file
444 * \li unsigned_8: Number of maximum players
445 */
446 NETCMD_DEDICATED_SAVED_GAMES = 31,
447
448 /**
449 * This is sent by the dedicated server to generate a clientsided translated system chat message.
450 * Payload is:
451 *423 *
452 * \li string: Message code \see NetworkGamingMessages::fill_map()424 * \li string: Message code \see NetworkGamingMessages::fill_map()
453 * \li string: First attached string425 * \li string: First attached string
454426
=== modified file 'src/sound/sound_handler.h'
--- src/sound/sound_handler.h 2015-10-18 15:41:10 +0000
+++ src/sound/sound_handler.h 2016-02-07 08:11:43 +0000
@@ -229,7 +229,6 @@
229 Widelands::EditorGameBase * egbase_;229 Widelands::EditorGameBase * egbase_;
230230
231 /** Only for buffering the command line option --nosound until real initialization is done.231 /** Only for buffering the command line option --nosound until real initialization is done.
232 * And disabling sound on dedicated servers
233 * \see SoundHandler::SoundHandler()232 * \see SoundHandler::SoundHandler()
234 * \see SoundHandler::init()233 * \see SoundHandler::init()
235 */234 */
236235
=== modified file 'src/ui_fsmenu/launch_mpg.cc'
--- src/ui_fsmenu/launch_mpg.cc 2016-02-04 09:10:44 +0000
+++ src/ui_fsmenu/launch_mpg.cc 2016-02-07 08:11:43 +0000
@@ -433,16 +433,6 @@
433 UI::WLMessageBox::MBoxType::kOk);433 UI::WLMessageBox::MBoxType::kOk);
434 warning.run<UI::Panel::Returncodes>();434 warning.run<UI::Panel::Returncodes>();
435 }435 }
436 } else {
437 if (!settings_ || settings_->settings().saved_games.empty())
438 throw wexception("A file was selected, that is not available to the client");
439 // this file is obviously a file from the dedicated server's saved games pool not available locally.
440 for (uint32_t i = 0; i < settings_->settings().saved_games.size(); ++i)
441 if (settings_->settings().saved_games.at(i).path == filename) {
442 settings_->set_map(filename, filename, settings_->settings().saved_games.at(i).players, true);
443 return;
444 }
445 throw wexception("The selected file could not be found in the pool of dedicated saved games.");
446 }436 }
447}437}
448438
449439
=== modified file 'src/ui_fsmenu/loadgame.cc'
--- src/ui_fsmenu/loadgame.cc 2016-02-04 09:10:44 +0000
+++ src/ui_fsmenu/loadgame.cc 2016-02-07 08:11:43 +0000
@@ -435,188 +435,173 @@
435 games_data_.clear();435 games_data_.clear();
436 table_.clear();436 table_.clear();
437437
438438 FilenameSet gamefiles;
439 if (settings_ && !settings_->settings().saved_games.empty()) {439
440 if (is_replay_) {
441 gamefiles = filter(g_fs->list_directory(REPLAY_DIR),
442 [](const std::string& fn) {return boost::ends_with(fn, REPLAY_SUFFIX);});
443 } else {
444 gamefiles = g_fs->list_directory("save");
445 }
446
447 Widelands::GamePreloadPacket gpdp;
448
449 for (const std::string& gamefilename : gamefiles) {
450 if (gamefilename == "save/campvis" || gamefilename == "save\\campvis") {
451 continue;
452 }
453
440 SavegameData gamedata;454 SavegameData gamedata;
441 for (uint32_t i = 0; i < settings_->settings().saved_games.size(); ++i) {455
442 gamedata.filename = settings_->settings().saved_games.at(i).path;456 std::string savename = gamefilename;
443 games_data_.push_back(gamedata);457 if (is_replay_) savename += WLGF_SUFFIX;
444458
445 UI::Table<uintptr_t const>::EntryRecord & te =459 if (!g_fs->file_exists(savename.c_str())) {
446 table_.add(games_data_.size() - 1);460 continue;
447 te.set_string(0, FileSystem::filename_without_ext(gamedata.filename.c_str()).c_str());461 }
448 }462
449 } else { // Normal case463 gamedata.filename = gamefilename;
450 // Fill it with all files we find.464
451465 try {
452 FilenameSet gamefiles;466 Widelands::GameLoader gl(savename.c_str(), game_);
453467 gl.preload_game(gpdp);
454 if (is_replay_) {468
455 gamefiles = filter(g_fs->list_directory(REPLAY_DIR),469 gamedata.gametype = gpdp.get_gametype();
456 [](const std::string& fn) {return boost::ends_with(fn, REPLAY_SUFFIX);});470
457 } else {471 if (!is_replay_) {
458 gamefiles = g_fs->list_directory("save");472 if (settings_->settings().multiplayer) {
459 }473 if (gamedata.gametype == GameController::GameType::SINGLEPLAYER) {
460
461 Widelands::GamePreloadPacket gpdp;
462
463 for (const std::string& gamefilename : gamefiles) {
464 if (gamefilename == "save/campvis" || gamefilename == "save\\campvis") {
465 continue;
466 }
467
468 SavegameData gamedata;
469
470 std::string savename = gamefilename;
471 if (is_replay_) savename += WLGF_SUFFIX;
472
473 if (!g_fs->file_exists(savename.c_str())) {
474 continue;
475 }
476
477 gamedata.filename = gamefilename;
478
479 try {
480 Widelands::GameLoader gl(savename.c_str(), game_);
481 gl.preload_game(gpdp);
482
483 gamedata.gametype = gpdp.get_gametype();
484
485 if (!is_replay_) {
486 if (settings_->settings().multiplayer) {
487 if (gamedata.gametype == GameController::GameType::SINGLEPLAYER) {
488 continue;
489 }
490 } else if (gamedata.gametype > GameController::GameType::SINGLEPLAYER) {
491 continue;474 continue;
492 }475 }
493 }476 } else if (gamedata.gametype > GameController::GameType::SINGLEPLAYER) {
494477 continue;
495 gamedata.mapname = gpdp.get_mapname();478 }
496 gamedata.gametime = gpdp.get_gametime();479 }
497 gamedata.nrplayers = gpdp.get_number_of_players();480
498 gamedata.version = gpdp.get_version();481 gamedata.mapname = gpdp.get_mapname();
499482 gamedata.gametime = gpdp.get_gametime();
500 gamedata.savetimestamp = gpdp.get_savetimestamp();483 gamedata.nrplayers = gpdp.get_number_of_players();
501 time_t t;484 gamedata.version = gpdp.get_version();
502 time(&t);485
503 struct tm * currenttime = localtime(&t);486 gamedata.savetimestamp = gpdp.get_savetimestamp();
504 // We need to put these into variables because of a sideeffect of the localtime function.487 time_t t;
505 int8_t current_year = currenttime->tm_year;488 time(&t);
506 int8_t current_month = currenttime->tm_mon;489 struct tm * currenttime = localtime(&t);
507 int8_t current_day = currenttime->tm_mday;490 // We need to put these into variables because of a sideeffect of the localtime function.
508491 int8_t current_year = currenttime->tm_year;
509 struct tm * savedate = localtime(&gamedata.savetimestamp);492 int8_t current_month = currenttime->tm_mon;
510493 int8_t current_day = currenttime->tm_mday;
511 if (gamedata.savetimestamp > 0) {494
512 if (savedate->tm_year == current_year &&495 struct tm * savedate = localtime(&gamedata.savetimestamp);
513 savedate->tm_mon == current_month &&496
514 savedate->tm_mday == current_day) { // Today497 if (gamedata.savetimestamp > 0) {
515498 if (savedate->tm_year == current_year &&
516 // Adding the 0 padding in a separate statement so translators won't have to deal with it499 savedate->tm_mon == current_month &&
517 const std::string minute = (boost::format("%02u") % savedate->tm_min).str();500 savedate->tm_mday == current_day) { // Today
518501
519 /** TRANSLATORS: Display date for choosing a savegame/replay */502 // Adding the 0 padding in a separate statement so translators won't have to deal with it
520 /** TRANSLATORS: hour:minute */503 const std::string minute = (boost::format("%02u") % savedate->tm_min).str();
521 gamedata.savedatestring = (boost::format(_("Today, %1%:%2%"))504
522 % savedate->tm_hour % minute).str();505 /** TRANSLATORS: Display date for choosing a savegame/replay */
523 } else if ((savedate->tm_year == current_year &&506 /** TRANSLATORS: hour:minute */
524 savedate->tm_mon == current_month &&507 gamedata.savedatestring = (boost::format(_("Today, %1%:%2%"))
525 savedate->tm_mday == current_day - 1) ||508 % savedate->tm_hour % minute).str();
526 (savedate->tm_year == current_year - 1 &&509 } else if ((savedate->tm_year == current_year &&
527 savedate->tm_mon == 11 && current_month == 0 &&510 savedate->tm_mon == current_month &&
528 savedate->tm_mday == 31 && current_day == 1)) { // Yesterday511 savedate->tm_mday == current_day - 1) ||
529 // Adding the 0 padding in a separate statement so translators won't have to deal with it512 (savedate->tm_year == current_year - 1 &&
530 const std::string minute = (boost::format("%02u") % savedate->tm_min).str();513 savedate->tm_mon == 11 && current_month == 0 &&
531514 savedate->tm_mday == 31 && current_day == 1)) { // Yesterday
532 /** TRANSLATORS: Display date for choosing a savegame/replay */515 // Adding the 0 padding in a separate statement so translators won't have to deal with it
533 /** TRANSLATORS: hour:minute */516 const std::string minute = (boost::format("%02u") % savedate->tm_min).str();
534 gamedata.savedatestring = (boost::format(_("Yesterday, %1%:%2%"))517
535 % savedate->tm_hour % minute).str();518 /** TRANSLATORS: Display date for choosing a savegame/replay */
536 } else { // Older519 /** TRANSLATORS: hour:minute */
537520 gamedata.savedatestring = (boost::format(_("Yesterday, %1%:%2%"))
538 /** TRANSLATORS: Display date for choosing a savegame/replay */521 % savedate->tm_hour % minute).str();
539 /** TRANSLATORS: month day, year */522 } else { // Older
540 gamedata.savedatestring = (boost::format(_("%2% %1%, %3%"))523
541 % savedate->tm_mday524 /** TRANSLATORS: Display date for choosing a savegame/replay */
542 % localize_month(savedate->tm_mon)525 /** TRANSLATORS: month day, year */
543 % (1900 + savedate->tm_year)).str();526 gamedata.savedatestring = (boost::format(_("%2% %1%, %3%"))
544 }527 % savedate->tm_mday
545 }528 % localize_month(savedate->tm_mon)
546529 % (1900 + savedate->tm_year)).str();
547 {530 }
548 i18n::Textdomain td("win_conditions");531 }
549 gamedata.wincondition = _(gpdp.get_win_condition());532
550 }533 {
551 gamedata.minimap_path = gpdp.get_minimap_path();534 i18n::Textdomain td("win_conditions");
552 games_data_.push_back(gamedata);535 gamedata.wincondition = _(gpdp.get_win_condition());
553536 }
554 UI::Table<uintptr_t const>::EntryRecord & te =537 gamedata.minimap_path = gpdp.get_minimap_path();
555 table_.add(games_data_.size() - 1);538 games_data_.push_back(gamedata);
556 te.set_string(0, gamedata.savedatestring);539
557540 UI::Table<uintptr_t const>::EntryRecord & te =
558 if (is_replay_ || settings_->settings().multiplayer) {541 table_.add(games_data_.size() - 1);
559 std::string gametypestring;542 te.set_string(0, gamedata.savedatestring);
560 switch (gamedata.gametype) {543
561 case GameController::GameType::SINGLEPLAYER:544 if (is_replay_ || settings_->settings().multiplayer) {
562 /** TRANSLATORS: "Single Player" entry in the Game Mode table column. */545 std::string gametypestring;
563 /** TRANSLATORS: "Keep this to 6 letters maximum. */546 switch (gamedata.gametype) {
564 /** TRANSLATORS: A tooltip will explain the abbreviation. */547 case GameController::GameType::SINGLEPLAYER:
565 /** TRANSLATORS: Make sure that this translation is consistent with the tooltip. */548 /** TRANSLATORS: "Single Player" entry in the Game Mode table column. */
566 gametypestring = _("SP");549 /** TRANSLATORS: "Keep this to 6 letters maximum. */
567 break;550 /** TRANSLATORS: A tooltip will explain the abbreviation. */
568 case GameController::GameType::NETHOST:551 /** TRANSLATORS: Make sure that this translation is consistent with the tooltip. */
569 /** TRANSLATORS: "Multiplayer Host" entry in the Game Mode table column. */552 gametypestring = _("SP");
570 /** TRANSLATORS: "Keep this to 2 letters maximum. */553 break;
571 /** TRANSLATORS: A tooltip will explain the abbreviation. */554 case GameController::GameType::NETHOST:
572 /** TRANSLATORS: Make sure that this translation is consistent with the tooltip. */555 /** TRANSLATORS: "Multiplayer Host" entry in the Game Mode table column. */
573 /** TRANSLATORS: %1% is the number of players */556 /** TRANSLATORS: "Keep this to 2 letters maximum. */
574 gametypestring = (boost::format(_("H (%1%)"))557 /** TRANSLATORS: A tooltip will explain the abbreviation. */
575 % static_cast<unsigned int>(gamedata.nrplayers)).str();558 /** TRANSLATORS: Make sure that this translation is consistent with the tooltip. */
576 break;559 /** TRANSLATORS: %1% is the number of players */
577 case GameController::GameType::NETCLIENT:560 gametypestring = (boost::format(_("H (%1%)"))
578 /** TRANSLATORS: "Multiplayer" entry in the Game Mode table column. */561 % static_cast<unsigned int>(gamedata.nrplayers)).str();
579 /** TRANSLATORS: "Keep this to 2 letters maximum. */562 break;
580 /** TRANSLATORS: A tooltip will explain the abbreviation. */563 case GameController::GameType::NETCLIENT:
581 /** TRANSLATORS: Make sure that this translation is consistent with the tooltip. */564 /** TRANSLATORS: "Multiplayer" entry in the Game Mode table column. */
582 /** TRANSLATORS: %1% is the number of players */565 /** TRANSLATORS: "Keep this to 2 letters maximum. */
583 gametypestring = (boost::format(_("MP (%1%)"))566 /** TRANSLATORS: A tooltip will explain the abbreviation. */
584 % static_cast<unsigned int>(gamedata.nrplayers)).str();567 /** TRANSLATORS: Make sure that this translation is consistent with the tooltip. */
585 break;568 /** TRANSLATORS: %1% is the number of players */
586 case GameController::GameType::REPLAY:569 gametypestring = (boost::format(_("MP (%1%)"))
587 gametypestring = "";570 % static_cast<unsigned int>(gamedata.nrplayers)).str();
588 break;571 break;
589 }572 case GameController::GameType::REPLAY:
590 te.set_string(1, gametypestring);573 gametypestring = "";
591 te.set_string(2, map_filename(gamedata.filename, gamedata.mapname));574 break;
592 } else {575 }
593 te.set_string(1, map_filename(gamedata.filename, gamedata.mapname));576 te.set_string(1, gametypestring);
594 }577 te.set_string(2, map_filename(gamedata.filename, gamedata.mapname));
595 } catch (const WException & e) {578 } else {
596 // we simply skip illegal entries579 te.set_string(1, map_filename(gamedata.filename, gamedata.mapname));
597 gamedata.errormessage =580 }
598 ((boost::format("%s\n\n%s\n\n%s"))581 } catch (const WException & e) {
599 /** TRANSLATORS: Error message introduction for when an old savegame can't be loaded */582 // we simply skip illegal entries
600 % _("This file has the wrong format and can’t be loaded."583 gamedata.errormessage =
601 " Maybe it was created with an older version of Widelands.")584 ((boost::format("%s\n\n%s\n\n%s"))
602 /** TRANSLATORS: This text is on a separate line with an error message below */585 /** TRANSLATORS: Error message introduction for when an old savegame can't be loaded */
603 % _("Error message:")586 % _("This file has the wrong format and can’t be loaded."
604 % e.what()).str();587 " Maybe it was created with an older version of Widelands.")
605588 /** TRANSLATORS: This text is on a separate line with an error message below */
606 const std::string fs_filename = FileSystem::filename_without_ext(gamedata.filename.c_str());589 % _("Error message:")
607 gamedata.mapname = fs_filename;590 % e.what()).str();
608 games_data_.push_back(gamedata);591
609592 const std::string fs_filename = FileSystem::filename_without_ext(gamedata.filename.c_str());
610 UI::Table<uintptr_t const>::EntryRecord & te =593 gamedata.mapname = fs_filename;
611 table_.add(games_data_.size() - 1);594 games_data_.push_back(gamedata);
612 te.set_string(0, "");595
613 if (is_replay_ || settings_->settings().multiplayer) {596 UI::Table<uintptr_t const>::EntryRecord & te =
614 te.set_string(1, "");597 table_.add(games_data_.size() - 1);
615 /** TRANSLATORS: Prefix for incompatible files in load game screens */598 te.set_string(0, "");
616 te.set_string(2, (boost::format(_("Incompatible: %s")) % fs_filename).str());599 if (is_replay_ || settings_->settings().multiplayer) {
617 } else {600 te.set_string(1, "");
618 te.set_string(1, (boost::format(_("Incompatible: %s")) % fs_filename).str());601 /** TRANSLATORS: Prefix for incompatible files in load game screens */
619 }602 te.set_string(2, (boost::format(_("Incompatible: %s")) % fs_filename).str());
603 } else {
604 te.set_string(1, (boost::format(_("Incompatible: %s")) % fs_filename).str());
620 }605 }
621 }606 }
622 }607 }
623608
=== modified file 'src/ui_fsmenu/mapselect.cc'
--- src/ui_fsmenu/mapselect.cc 2016-01-29 08:37:22 +0000
+++ src/ui_fsmenu/mapselect.cc 2016-02-07 08:11:43 +0000
@@ -214,9 +214,6 @@
214 * The search starts in \ref curdir_ ("..../maps") and there is no possibility214 * The search starts in \ref curdir_ ("..../maps") and there is no possibility
215 * to move further up. If the user moves down into subdirectories, we insert an215 * to move further up. If the user moves down into subdirectories, we insert an
216 * entry to move back up.216 * entry to move back up.
217 *
218 * \note special case is, if this is a multiplayer game on a dedicated server and
219 * the client wants to change the map - in that case the maps available on the server are shown.
220 */217 */
221void FullscreenMenuMapSelect::fill_table()218void FullscreenMenuMapSelect::fill_table()
222{219{
@@ -231,137 +228,66 @@
231 display_type = MapData::DisplayType::kMapnamesLocalized;228 display_type = MapData::DisplayType::kMapnamesLocalized;
232 }229 }
233230
234 if (settings_->settings().maps.empty()) {231 // This is the normal case
235 // This is the normal case232
236233 // Fill it with all files we find in all directories.
237 // Fill it with all files we find in all directories.234 FilenameSet files = g_fs->list_directory(curdir_);
238 FilenameSet files = g_fs->list_directory(curdir_);235
239236 //If we are not at the top of the map directory hierarchy (we're not talking
240 //If we are not at the top of the map directory hierarchy (we're not talking237 //about the absolute filesystem top!) we manually add ".."
241 //about the absolute filesystem top!) we manually add ".."238 if (curdir_ != basedir_) {
242 if (curdir_ != basedir_) {239 maps_data_.push_back(MapData::create_parent_dir(curdir_));
243 maps_data_.push_back(MapData::create_parent_dir(curdir_));240 }
244 }241
245242 Widelands::Map map; // MapLoader needs a place to put its preload data
246 Widelands::Map map; // MapLoader needs a place to put its preload data243
247244 for (const std::string& mapfilename : files) {
248 for (const std::string& mapfilename : files) {245 // Add map file (compressed) or map directory (uncompressed)
249 // Add map file (compressed) or map directory (uncompressed)246 std::unique_ptr<Widelands::MapLoader> ml = map.get_correct_loader(mapfilename);
250 std::unique_ptr<Widelands::MapLoader> ml = map.get_correct_loader(mapfilename);247 if (ml != nullptr) {
251 if (ml != nullptr) {
252 try {
253 map.set_filename(mapfilename);
254 ml->preload_map(true);
255
256 if (!map.get_width() || !map.get_height()) {
257 continue;
258 }
259
260 MapData::MapType maptype;
261 if (map.scenario_types() & scenario_types_) {
262 maptype = MapData::MapType::kScenario;
263 } else if (dynamic_cast<WidelandsMapLoader*>(ml.get())) {
264 maptype = MapData::MapType::kNormal;
265 } else {
266 maptype = MapData::MapType::kSettlers2;
267 }
268
269 MapData mapdata(map, mapfilename, maptype, display_type);
270
271 has_translated_mapname_ =
272 has_translated_mapname_ || (mapdata.name != mapdata.localized_name);
273
274 bool has_all_tags = true;
275 for (std::set<uint32_t>::const_iterator it = req_tags_.begin(); it != req_tags_.end(); ++it)
276 has_all_tags &= mapdata.tags.count(tags_ordered_[*it]);
277 if (!has_all_tags) {
278 continue;
279 }
280 maps_data_.push_back(mapdata);
281 } catch (const std::exception & e) {
282 log("Mapselect: Skip %s due to preload error: %s\n", mapfilename.c_str(), e.what());
283 } catch (...) {
284 log("Mapselect: Skip %s due to unknown exception\n", mapfilename.c_str());
285 }
286 } else if (g_fs->is_directory(mapfilename)) {
287 // Add subdirectory to the list
288 const char* fs_filename = FileSystem::fs_filename(mapfilename.c_str());
289 if (!strcmp(fs_filename, ".") || !strcmp(fs_filename, ".."))
290 continue;
291 maps_data_.push_back(MapData::create_directory(mapfilename));
292 }
293 }
294 } else {
295 //client changing maps on dedicated server
296 for (uint16_t i = 0; i < settings_->settings().maps.size(); ++i) {
297 Widelands::Map map; // MapLoader needs a place to put its preload data
298
299 const DedicatedMapInfos & dmap = settings_->settings().maps.at(i);
300 const std::string& mapfilename = dmap.path;
301 std::unique_ptr<Widelands::MapLoader> ml(map.get_correct_loader(mapfilename));
302
303 try {248 try {
304 if (!ml) {
305 throw wexception("Mapselect: No MapLoader");
306 }
307
308 map.set_filename(mapfilename);249 map.set_filename(mapfilename);
309 ml->preload_map(true);250 ml->preload_map(true);
310251
311 if (!map.get_width() || !map.get_height()) {252 if (!map.get_width() || !map.get_height()) {
312 throw wexception("Mapselect: Map has no size");253 continue;
313 }254 }
314255
315 MapData::MapType maptype;256 MapData::MapType maptype;
316
317 if (map.scenario_types() & scenario_types_) {257 if (map.scenario_types() & scenario_types_) {
318 maptype = MapData::MapType::kScenario;258 maptype = MapData::MapType::kScenario;
319 } else if (dynamic_cast<WidelandsMapLoader*>(ml.get())) {259 } else if (dynamic_cast<WidelandsMapLoader*>(ml.get())) {
260 maptype = MapData::MapType::kNormal;
261 } else {
320 maptype = MapData::MapType::kSettlers2;262 maptype = MapData::MapType::kSettlers2;
321 } else {
322 maptype = MapData::MapType::kNormal;
323 }
324
325 if (map.get_nrplayers() != dmap.players ||
326 (maptype == MapData::MapType::kScenario) != dmap.scenario) {
327 throw wexception("Mapselect: Number of players or scenario doesn't match");
328 }263 }
329264
330 MapData mapdata(map, mapfilename, maptype, display_type);265 MapData mapdata(map, mapfilename, maptype, display_type);
331266
332 // Finally write the entry to the list267 has_translated_mapname_ =
268 has_translated_mapname_ || (mapdata.name != mapdata.localized_name);
269
270 bool has_all_tags = true;
271 for (std::set<uint32_t>::const_iterator it = req_tags_.begin(); it != req_tags_.end(); ++it)
272 has_all_tags &= mapdata.tags.count(tags_ordered_[*it]);
273 if (!has_all_tags) {
274 continue;
275 }
333 maps_data_.push_back(mapdata);276 maps_data_.push_back(mapdata);
277 } catch (const std::exception & e) {
278 log("Mapselect: Skip %s due to preload error: %s\n", mapfilename.c_str(), e.what());
334 } catch (...) {279 } catch (...) {
335 log("Mapselect: Skipped reading locale data for file %s - not valid.\n", mapfilename.c_str());280 log("Mapselect: Skip %s due to unknown exception\n", mapfilename.c_str());
336
337 MapData mapdata;
338
339 // Fill in the data we got from the dedicated server
340 mapdata.filename = mapfilename;
341 mapdata.name = mapfilename.substr(5, mapfilename.size() - 1);
342 mapdata.authors = MapAuthorData(_("Nobody"));
343 mapdata.description = _("This map file is not present in your filesystem."
344 " The data shown here was sent by the server.");
345 mapdata.hint = "";
346 mapdata.nrplayers = dmap.players;
347 mapdata.width = 1;
348 mapdata.height = 0;
349 mapdata.displaytype = display_type;
350
351 if (dmap.scenario) {
352 mapdata.maptype = MapData::MapType::kScenario;
353 mapdata.tags.insert("scenario");
354 } else if (dynamic_cast<WidelandsMapLoader*>(ml.get())) {
355 mapdata.maptype = MapData::MapType::kSettlers2;
356 } else {
357 mapdata.maptype = MapData::MapType::kNormal;
358 }
359
360 // Finally write the entry to the list
361 maps_data_.push_back(mapdata);
362 }281 }
282 } else if (g_fs->is_directory(mapfilename)) {
283 // Add subdirectory to the list
284 const char* fs_filename = FileSystem::fs_filename(mapfilename.c_str());
285 if (!strcmp(fs_filename, ".") || !strcmp(fs_filename, ".."))
286 continue;
287 maps_data_.push_back(MapData::create_directory(mapfilename));
363 }288 }
364 }289 }
290
365 table_.fill(maps_data_, display_type);291 table_.fill(maps_data_, display_type);
366 if (!table_.empty()) {292 if (!table_.empty()) {
367 table_.select(0);293 table_.select(0);
368294
=== modified file 'src/wlapplication.cc'
--- src/wlapplication.cc 2016-02-06 19:58:38 +0000
+++ src/wlapplication.cc 2016-02-07 08:11:43 +0000
@@ -57,7 +57,6 @@
57#include "graphic/text/font_set.h"57#include "graphic/text/font_set.h"
58#include "graphic/text_constants.h"58#include "graphic/text_constants.h"
59#include "helper.h"59#include "helper.h"
60#include "io/dedicated_log.h"
61#include "io/filesystem/disk_filesystem.h"60#include "io/filesystem/disk_filesystem.h"
62#include "io/filesystem/layered_filesystem.h"61#include "io/filesystem/layered_filesystem.h"
63#include "logic/game.h"62#include "logic/game.h"
@@ -391,68 +390,6 @@
391 emergency_save(game);390 emergency_save(game);
392 throw;391 throw;
393 }392 }
394 } else if (game_type_ == INTERNET) {
395 Widelands::Game game;
396 try {
397 // disable sound completely
398 g_sound_handler.nosound_ = true;
399
400 // setup some details of the dedicated server
401 Section & s = g_options.pull_section ("global");
402 const std::string & meta = s.get_string ("metaserver", INTERNET_GAMING_METASERVER.c_str());
403 uint32_t port = s.get_natural("metaserverport", INTERNET_GAMING_PORT);
404 const std::string & name = s.get_string ("nickname", "dedicated");
405 const std::string & server = s.get_string ("servername", name.c_str());
406 const bool registered = s.get_bool ("registered", false);
407 const std::string & pwd = s.get_string ("password", "");
408 for (;;) { // endless loop
409 if (!InternetGaming::ref().login(name, pwd, registered, meta, port)) {
410 dedicatedlog("ERROR: Could not connect to metaserver (reason above)!\n");
411 return;
412 }
413 std::string realservername(server);
414 bool name_valid = false;
415 while (!name_valid) {
416 name_valid = true;
417 const std::vector<InternetGame> & hosts = InternetGaming::ref().games();
418 for (uint32_t i = 0; i < hosts.size(); ++i) {
419 if (hosts.at(i).name == realservername)
420 name_valid = false;
421 }
422 if (!name_valid)
423 realservername += "*";
424 }
425
426 InternetGaming::ref().set_local_servername(realservername);
427
428 NetHost netgame(name, true);
429
430 // Load the requested map
431 Widelands::Map map;
432 map.set_filename(filename_);
433 std::unique_ptr<Widelands::MapLoader> ml = map.get_correct_loader(filename_);
434 if (!ml) {
435 throw WLWarning
436 ("Unsupported format",
437 "Widelands could not load the file \"%s\". The file format seems to be incompatible.",
438 filename_.c_str());
439 }
440 ml->preload_map(true);
441
442 // set the map
443 netgame.set_map(map.get_name(), map.get_filename(), map.get_nrplayers());
444
445 // run the network game
446 // -> autostarts when a player sends "/start" as pm to the server.
447 netgame.run(true);
448
449 InternetGaming::ref().logout();
450 }
451 } catch (const std::exception & e) {
452 log("Fatal exception: %s\n", e.what());
453 emergency_save(game);
454 throw;
455 }
456 } else {393 } else {
457 g_sound_handler.start_music("intro");394 g_sound_handler.start_music("intro");
458395
@@ -749,7 +686,6 @@
749 s.get_bool("remove_syncstreams");686 s.get_bool("remove_syncstreams");
750 s.get_bool("sound_at_message");687 s.get_bool("sound_at_message");
751 s.get_bool("transparent_chat");688 s.get_bool("transparent_chat");
752 s.get_bool("dedicated_saving"); // saving via chatcommand on dedicated servers -> nethost.cc
753 s.get_string("registered");689 s.get_string("registered");
754 s.get_string("nickname");690 s.get_string("nickname");
755 s.get_string("password");691 s.get_string("password");
@@ -958,17 +894,6 @@
958 game_type_ = SCENARIO;894 game_type_ = SCENARIO;
959 commandline_.erase("scenario");895 commandline_.erase("scenario");
960 }896 }
961 if (commandline_.count("dedicated")) {
962 if (game_type_ != NONE)
963 throw wexception("dedicated can not be combined with other actions");
964 filename_ = commandline_["dedicated"];
965 if (filename_.empty())
966 throw wexception("empty value of commandline parameter --dedicated");
967 if (*filename_.rbegin() == '/')
968 filename_.erase(filename_.size() - 1);
969 game_type_ = INTERNET;
970 commandline_.erase("dedicated");
971 }
972 if (commandline_.count("script")) {897 if (commandline_.count("script")) {
973 script_to_run_ = commandline_["script"];898 script_to_run_ = commandline_["script"];
974 if (script_to_run_.empty())899 if (script_to_run_.empty())
@@ -1297,7 +1222,7 @@
12971222
1298 game.set_game_controller(ctrl.get());1223 game.set_game_controller(ctrl.get());
1299 game.init_newgame(&loader_ui, sp.settings());1224 game.init_newgame(&loader_ui, sp.settings());
1300 game.run(&loader_ui, Widelands::Game::NewNonScenario, "", false);1225 game.run(&loader_ui, Widelands::Game::NewNonScenario, "", false, "single_player");
1301 } catch (const std::exception & e) {1226 } catch (const std::exception & e) {
1302 log("Fatal exception: %s\n", e.what());1227 log("Fatal exception: %s\n", e.what());
1303 emergency_save(game);1228 emergency_save(game);
@@ -1412,7 +1337,7 @@
14121337
1413 game.save_handler().set_allow_saving(false);1338 game.save_handler().set_allow_saving(false);
14141339
1415 game.run(&loader_ui, Widelands::Game::Loaded, "", true);1340 game.run(&loader_ui, Widelands::Game::Loaded, "", true, "replay");
1416 } catch (const std::exception & e) {1341 } catch (const std::exception & e) {
1417 log("Fatal Exception: %s\n", e.what());1342 log("Fatal Exception: %s\n", e.what());
1418 emergency_save(game);1343 emergency_save(game);
14191344
=== modified file 'src/wlapplication.h'
--- src/wlapplication.h 2016-01-28 05:24:34 +0000
+++ src/wlapplication.h 2016-02-07 08:11:43 +0000
@@ -135,7 +135,7 @@
135 static WLApplication * get(int const argc = 0, char const * * argv = nullptr);135 static WLApplication * get(int const argc = 0, char const * * argv = nullptr);
136 ~WLApplication();136 ~WLApplication();
137137
138 enum GameType {NONE, EDITOR, REPLAY, SCENARIO, LOADGAME, NETWORK, INTERNET};138 enum GameType {NONE, EDITOR, REPLAY, SCENARIO, LOADGAME, NETWORK};
139139
140 void run();140 void run();
141141
142142
=== modified file 'src/wlapplication_messages.cc'
--- src/wlapplication_messages.cc 2015-01-12 15:44:52 +0000
+++ src/wlapplication_messages.cc 2016-02-07 08:11:43 +0000
@@ -85,7 +85,6 @@
85 << _(" --loadgame=FILENAME Directly loads the savegame FILENAME.") << endl85 << _(" --loadgame=FILENAME Directly loads the savegame FILENAME.") << endl
86 << _(" --script=FILENAME Run the given Lua script after initialization.\n"86 << _(" --script=FILENAME Run the given Lua script after initialization.\n"
87 " Only valid with --scenario, --loadgame, or --editor.") << endl87 " Only valid with --scenario, --loadgame, or --editor.") << endl
88 << _(" --dedicated=FILENAME Starts a dedicated server with FILENAME as map") << endl
89 /** TRANSLATORS: You may translate true/false, also as on/off or yes/no, but */88 /** TRANSLATORS: You may translate true/false, also as on/off or yes/no, but */
90 /** TRANSLATORS: it HAS TO BE CONSISTENT with the translation in the widelands textdomain */89 /** TRANSLATORS: it HAS TO BE CONSISTENT with the translation in the widelands textdomain */
91 << _(" --auto_roadbuild_mode=[true|false]\n"90 << _(" --auto_roadbuild_mode=[true|false]\n"
9291
=== modified file 'src/wui/chat_msg_layout.cc'
--- src/wui/chat_msg_layout.cc 2015-03-17 21:29:04 +0000
+++ src/wui/chat_msg_layout.cc 2016-02-07 08:11:43 +0000
@@ -58,8 +58,7 @@
58 //58 //
59 // Note that we do want host and meta server to send some richtext code,59 // Note that we do want host and meta server to send some richtext code,
60 // as the ability to send formatted commands is nice for the usability60 // as the ability to send formatted commands is nice for the usability
61 // of meta server and dedicated servers, so we're treading a bit of a61 // of meta server so we're treading a bit of a fine line here.
62 // fine line here.
63 std::string sanitized;62 std::string sanitized;
64 for (std::string::size_type pos = 0; pos < chat_message.msg.size(); ++pos) {63 for (std::string::size_type pos = 0; pos < chat_message.msg.size(); ++pos) {
65 if (chat_message.msg[pos] == '<') {64 if (chat_message.msg[pos] == '<') {
@@ -157,8 +156,7 @@
157 //156 //
158 // Note that we do want host and meta server to send some richtext code,157 // Note that we do want host and meta server to send some richtext code,
159 // as the ability to send formatted commands is nice for the usability158 // as the ability to send formatted commands is nice for the usability
160 // of meta server and dedicated servers, so we're treading a bit of a159 // of meta server so we're treading a bit of a fine line here.
161 // fine line here.
162 std::string sanitized;160 std::string sanitized;
163 for (std::string::size_type pos = 0; pos < chat_message.msg.size(); ++pos) {161 for (std::string::size_type pos = 0; pos < chat_message.msg.size(); ++pos) {
164 if (chat_message.msg[pos] == '<') {162 if (chat_message.msg[pos] == '<') {

Subscribers

People subscribed via source and target branches

to status/vote changes: