Merge lp:~widelands-dev/widelands/bug-1434875-net-client-disconnect into lp:widelands
- bug-1434875-net-client-disconnect
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 8831 | ||||
Proposed branch: | lp:~widelands-dev/widelands/bug-1434875-net-client-disconnect | ||||
Merge into: | lp:widelands | ||||
Diff against target: |
600 lines (+401/-29) 12 files modified
src/network/gamehost.cc (+49/-2) src/network/gamehost.h (+2/-0) src/network/network_gaming_messages.cc (+1/-0) src/ui_basic/unique_window.cc (+3/-2) src/wui/CMakeLists.txt (+4/-0) src/wui/game_client_disconnected.cc (+178/-0) src/wui/game_client_disconnected.h (+62/-0) src/wui/game_exit_confirm_box.cc (+43/-0) src/wui/game_exit_confirm_box.h (+41/-0) src/wui/game_options_menu.cc (+2/-25) src/wui/interactive_gamebase.cc (+13/-0) src/wui/interactive_gamebase.h (+3/-0) |
||||
To merge this branch: | bzr merge lp:~widelands-dev/widelands/bug-1434875-net-client-disconnect | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
GunChleoc | Approve | ||
Review via email:
|
Commit message
Adding a dialog for the host when the connection to a client is lost. Allows the host to select whether to replace the client with an AI or to exit.
Description of the change
When a client disconnects (either on purpose or due to network errors), the game is paused, saved, and a dialog is displayed to the host. There, the host can select whether to replace the client with a Normal/Weak/Very Weak/Empty AI or to exit the game.
No dialog is shown, if the leaving player ...
- is only an observer
- has already lost. In that case the player is replaced by the Empty AI
- has won the game. In that case the player is replaced by the Normal AI
So far, this branch seems to work fine in my testcases and could be merged.
[ignore next part, not an issue of this branch]
However, ASAN is complaining about access to already freed memory when the host closes the game with Alt+F4 while the dialog is shown. Strangely, there is no complain if the "really exit game" confirmation dialog has been shown but aborted.
I wasn't able to figure out what is happening there. So if someone has an idea what is causing the problem, please tell me or fix it yourself. Apart from this memory bug, the branch is ready for review and testing.
[/ignore]
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
bunnybot (widelandsofficial) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 3925. State: failed. Details: https:/
Appveyor build 3723. State: failed. Details: https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
GunChleoc (gunchleoc) wrote : | # |
I have not been able to fix the memory leak.
The heart of the problem is that dropdowns break the expected tree hierarchy for panels by necessity - otherwise, we would not be able to show the list outside of the enclosing box. We have continually been struggling with this.
It's also weir that the same problem doesn't happen for the editor player menu, where we also have dropdowns inside a box inside a unique window.
I think we need to change the panel implementation to use shared_ptr instead of raw pointers. I have too many UI branches open at this time to do this now though - the changes will be huge and cause merge conflicts all over the place.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Notabilis (notabilis27) wrote : | # |
Thanks for the explanation, it makes much more sense now. I haven't considered that the dropbox needs to access "higher" parents, so it was quite a strange effect. But I guess that means that this branch isn't to blame and can be reviewed and merged.
Would you mind copying your explanation to a new bug report about the memory leak and targeting it for build-21? The leak doesn't seem to cause any immediate harm so I think we can postpone fixing it until your other branches are in.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
GunChleoc (gunchleoc) wrote : | # |
Bug is up: https:/
I have 1 more idea for the memory leak. I'll try to fix it and then start the code review.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
GunChleoc (gunchleoc) wrote : | # |
I suggested some improvements for the i18n. There is also some code duplication that we should get rid of.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 3945. State: passed. Details: https:/
Appveyor build 3743. State: success. Details: https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Notabilis (notabilis27) wrote : | # |
Thanks for the bug report, the local fix and the review. Your remarks are hopefully all fixed now.
Do we need a translator comment for both occurrences of "Replace with %s" or is one comment enough when it is the same string?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 3958. State: errored. Details: https:/
Appveyor build 3756. State: success. Details: https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 3965. State: passed. Details: https:/
Appveyor build 3763. State: success. Details: https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
GunChleoc (gunchleoc) wrote : | # |
I have tweaked the strings some more - all good now :)
> Do we need a translator comment for both occurrences of "Replace with %s" or is one comment enough when it is the same string?
One comment is enough - Gettext uses the string as a key, so it will be presented for translation only once. We can disambiguate them with pgettext when needed.
@bunnybot merge
Preview Diff
1 | === modified file 'src/network/gamehost.cc' |
2 | --- src/network/gamehost.cc 2018-04-07 16:59:00 +0000 |
3 | +++ src/network/gamehost.cc 2018-09-14 08:20:24 +0000 |
4 | @@ -31,6 +31,7 @@ |
5 | #endif |
6 | |
7 | #include "ai/computer_player.h" |
8 | +#include "ai/defaultai.h" |
9 | #include "base/i18n.h" |
10 | #include "base/md5.h" |
11 | #include "base/warning.h" |
12 | @@ -560,6 +561,25 @@ |
13 | ->instantiate(*d->game, p)); |
14 | } |
15 | |
16 | +void GameHost::replace_client_with_ai(uint8_t playernumber, const std::string& ai) { |
17 | + assert(d->game->get_player(playernumber + 1)->get_ai().empty()); |
18 | + assert(d->game->get_player(playernumber + 1)->get_ai() |
19 | + == d->settings.players.at(playernumber).ai); |
20 | + // Inform all players about the change |
21 | + // Has to be done at first in this method since the calls later on overwrite players[].name |
22 | + send_system_message_code( |
23 | + "CLIENT_X_REPLACED_WITH", |
24 | + d->settings.players.at(playernumber).name, |
25 | + ComputerPlayer::get_implementation(ai)->descname); |
26 | + set_player_ai(playernumber, ai, false); |
27 | + d->game->get_player(playernumber + 1)->set_ai(ai); |
28 | + // Activate the ai |
29 | + init_computer_player(playernumber + 1); |
30 | + set_player_state(playernumber, PlayerSettings::State::kComputer); |
31 | + assert(d->game->get_player(playernumber + 1)->get_ai() |
32 | + == d->settings.players.at(playernumber).ai); |
33 | +} |
34 | + |
35 | void GameHost::init_computer_players() { |
36 | const Widelands::PlayerNumber nr_players = d->game->map().get_nrplayers(); |
37 | iterate_players_existing_novar(p, nr_players, *d->game) { |
38 | @@ -2254,8 +2274,7 @@ |
39 | } |
40 | |
41 | set_player_state(number, PlayerSettings::State::kOpen); |
42 | - if (d->game) |
43 | - init_computer_player(number + 1); |
44 | + // Don't replace player with AI, let host choose what to do |
45 | } |
46 | |
47 | void GameHost::disconnect_client(uint32_t const number, |
48 | @@ -2266,6 +2285,34 @@ |
49 | |
50 | Client& client = d->clients.at(number); |
51 | |
52 | + // If the client is linked to a player and it is the client that closes the connection |
53 | + // and the game has already started ... |
54 | + if (client.playernum != UserSettings::none() && reason != "SERVER_LEFT" && d->game != nullptr) { |
55 | + // And the client hasn't lost/won yet ... |
56 | + if (d->settings.users.at(client.usernum).result == Widelands::PlayerEndResult::kUndefined) { |
57 | + // If not shown yet, show a window and ask the host player what to do |
58 | + // with the tribe of the leaving client |
59 | + if (d->game->get_igbase()->show_game_client_disconnected()) { |
60 | + // Window has just been opened, pause game and create a save game |
61 | + if (!forced_pause()) { |
62 | + force_pause(); |
63 | + } |
64 | + WLApplication::emergency_save(*d->game); |
65 | + } |
66 | + // Client was active but is a winner of the game: Replace with normal AI |
67 | + } else if (d->settings.users.at(client.usernum).result |
68 | + == Widelands::PlayerEndResult::kWon) { |
69 | + replace_client_with_ai(client.playernum, DefaultAI::normal_impl.name); |
70 | + // Client was active but has lost or gave up: Replace with empty AI |
71 | + } else { |
72 | + assert(d->settings.users.at(client.usernum).result |
73 | + == Widelands::PlayerEndResult::kLost |
74 | + || d->settings.users.at(client.usernum).result |
75 | + == Widelands::PlayerEndResult::kResigned); |
76 | + replace_client_with_ai(client.playernum, "empty"); |
77 | + } |
78 | + } |
79 | + |
80 | // If the client was completely connected before the disconnect, free the |
81 | // user settings and send changes to the clients |
82 | if (client.usernum >= 0) { |
83 | |
84 | === modified file 'src/network/gamehost.h' |
85 | --- src/network/gamehost.h 2018-04-07 16:59:00 +0000 |
86 | +++ src/network/gamehost.h 2018-09-14 08:20:24 +0000 |
87 | @@ -26,6 +26,7 @@ |
88 | #include "logic/widelands.h" |
89 | #include "network/nethost_interface.h" |
90 | #include "network/network.h" |
91 | +#include "ui_basic/unique_window.h" |
92 | |
93 | struct ChatMessage; |
94 | struct GameHostImpl; |
95 | @@ -79,6 +80,7 @@ |
96 | void set_player_shared(PlayerSlot number, Widelands::PlayerNumber shared); |
97 | void switch_to_player(uint32_t user, uint8_t number); |
98 | void set_win_condition_script(const std::string& wc); |
99 | + void replace_client_with_ai(uint8_t playernumber, const std::string& ai); |
100 | |
101 | // just visible stuff for the select mapmenu |
102 | void set_multiplayer_game_settings(); |
103 | |
104 | === modified file 'src/network/network_gaming_messages.cc' |
105 | --- src/network/network_gaming_messages.cc 2018-04-07 16:59:00 +0000 |
106 | +++ src/network/network_gaming_messages.cc 2018-09-14 08:20:24 +0000 |
107 | @@ -128,6 +128,7 @@ |
108 | ngmessages["MALFORMED_COMMANDS"] = _("Client sent malformed commands: %s"); |
109 | ngmessages["SOMETHING_WRONG"] = _("Something went wrong: %s"); |
110 | ngmessages["CLIENT_X_LEFT_GAME"] = _("%1$s has left the game (%2$s)"); |
111 | + ngmessages["CLIENT_X_REPLACED_WITH"] = _("%1$s has been replaced with %2$s"); |
112 | ngmessages["UNKNOWN_LEFT_GAME"] = _("Unknown user has left the game (%s)"); |
113 | ngmessages["SYNCREQUEST_WO_GAME"] = |
114 | _("Server sent a SYNCREQUEST even though no game is running."); |
115 | |
116 | === modified file 'src/ui_basic/unique_window.cc' |
117 | --- src/ui_basic/unique_window.cc 2018-04-27 06:11:05 +0000 |
118 | +++ src/ui_basic/unique_window.cc 2018-09-14 08:20:24 +0000 |
119 | @@ -37,14 +37,15 @@ |
120 | if (!window) { |
121 | open_window(); |
122 | } else { |
123 | - if (window->is_minimal()) |
124 | + if (window->is_minimal()) { |
125 | window->restore(); |
126 | + } |
127 | window->move_to_top(); |
128 | } |
129 | } |
130 | |
131 | /** |
132 | - * Destroys the window, if it eixsts. |
133 | + * Destroys the window, if it exists. |
134 | */ |
135 | void UniqueWindow::Registry::destroy() { |
136 | if (window) { |
137 | |
138 | === modified file 'src/wui/CMakeLists.txt' |
139 | --- src/wui/CMakeLists.txt 2018-05-16 05:30:22 +0000 |
140 | +++ src/wui/CMakeLists.txt 2018-09-14 08:20:24 +0000 |
141 | @@ -175,8 +175,12 @@ |
142 | encyclopedia_window.h |
143 | fieldaction.cc |
144 | fieldaction.h |
145 | + game_client_disconnected.cc |
146 | + game_client_disconnected.h |
147 | game_debug_ui.cc |
148 | game_debug_ui.h |
149 | + game_exit_confirm_box.cc |
150 | + game_exit_confirm_box.h |
151 | game_statistics_menu.cc |
152 | game_statistics_menu.h |
153 | game_main_menu_save_game.cc |
154 | |
155 | === added file 'src/wui/game_client_disconnected.cc' |
156 | --- src/wui/game_client_disconnected.cc 1970-01-01 00:00:00 +0000 |
157 | +++ src/wui/game_client_disconnected.cc 2018-09-14 08:20:24 +0000 |
158 | @@ -0,0 +1,178 @@ |
159 | +/* |
160 | + * Copyright (C) 2002-2018 by the Widelands Development Team |
161 | + * |
162 | + * This program is free software; you can redistribute it and/or |
163 | + * modify it under the terms of the GNU General Public License |
164 | + * as published by the Free Software Foundation; either version 2 |
165 | + * of the License, or (at your option) any later version. |
166 | + * |
167 | + * This program is distributed in the hope that it will be useful, |
168 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
169 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
170 | + * GNU General Public License for more details. |
171 | + * |
172 | + * You should have received a copy of the GNU General Public License |
173 | + * along with this program; if not, write to the Free Software |
174 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
175 | + * |
176 | + */ |
177 | + |
178 | +#include "wui/game_client_disconnected.h" |
179 | + |
180 | +#include <boost/bind.hpp> |
181 | +#include <boost/format.hpp> |
182 | + |
183 | +#include "ai/computer_player.h" |
184 | +#include "ai/defaultai.h" |
185 | +#include "base/i18n.h" |
186 | +#include "network/gamehost.h" |
187 | +#include "wui/game_exit_confirm_box.h" |
188 | +#include "wui/interactive_gamebase.h" |
189 | + |
190 | +namespace { |
191 | + |
192 | +constexpr int32_t width = 256; |
193 | +constexpr int32_t margin = 10; |
194 | +constexpr int32_t vspacing = 5; |
195 | +constexpr uint32_t vgap = 3; |
196 | + |
197 | +} // end anonymous namespace |
198 | + |
199 | +GameClientDisconnected::GameClientDisconnected(InteractiveGameBase* gb, |
200 | + UI::UniqueWindow::Registry& registry, |
201 | + GameHost* host) |
202 | + : UI::UniqueWindow(gb, "client_disconnected", ®istry, 2 * margin + width, 0, |
203 | + /** TRANSLATORS: Window label */ |
204 | + _("Client got disconnected")), |
205 | + igb_(gb), |
206 | + host_(host), |
207 | + box_(this, margin, margin, UI::Box::Vertical, width, get_h() - 2 * margin, vspacing), |
208 | + box_h_(&box_, margin, margin, UI::Box::Horizontal, width, 35, vspacing), |
209 | + text_(&box_, |
210 | + 0, |
211 | + 0, |
212 | + width, |
213 | + 10, // automatic height |
214 | + UI::PanelStyle::kWui, |
215 | + _("A player disconnected from the game. An automatic save game has been created. " |
216 | + "Do you want to continue playing?"), |
217 | + UI::Align::kLeft, |
218 | + UI::MultilineTextarea::ScrollMode::kNoScrolling), |
219 | + continue_(&box_h_, |
220 | + "continue_game", |
221 | + 0, |
222 | + 0, |
223 | + width - 35 - vspacing, |
224 | + 35, |
225 | + UI::ButtonStyle::kWuiMenu, |
226 | + /** TRANSLATORS: Button text */ |
227 | + _("Continue game"), |
228 | + /** TRANSLATORS: Button tooltip */ |
229 | + _("Replace the disconnected player with the selected AI and continue playing")), |
230 | + type_dropdown_(&box_h_, |
231 | + width - 50, // x |
232 | + 0, // y |
233 | + 60, // width of selection box |
234 | + 800, // height of selection box, shrinks automatically |
235 | + 35, // width/height of button |
236 | + /** TRANSLATORS: Dropdown tooltip to select the AI difficulty when a player has disconnected from a game */ |
237 | + _("AI for the disconnected player"), |
238 | + UI::DropdownType::kPictorial, |
239 | + UI::PanelStyle::kWui), |
240 | + exit_game_(&box_, |
241 | + "exit_game", |
242 | + 0, |
243 | + 0, |
244 | + width, |
245 | + 35, |
246 | + UI::ButtonStyle::kWuiMenu, |
247 | + g_gr->images().get("images/wui/menus/menu_exit_game.png"), |
248 | + /** TRANSLATORS: Button tooltip */ |
249 | + _("Exit Game")) { |
250 | + |
251 | + box_.add(&text_); |
252 | + box_.add_space(vgap); |
253 | + box_h_.add(&continue_); |
254 | + box_h_.add(&type_dropdown_); |
255 | + box_.add(&box_h_); |
256 | + box_.add(&exit_game_); |
257 | + box_.set_size(width, text_.get_h() + vgap + box_h_.get_h() + exit_game_.get_h() + 3 * vspacing); |
258 | + set_inner_size(get_inner_w(), box_.get_h() + 2 * margin); |
259 | + |
260 | + continue_.sigclicked.connect( |
261 | + boost::bind(&GameClientDisconnected::clicked_continue, boost::ref(*this))); |
262 | + exit_game_.sigclicked.connect( |
263 | + boost::bind(&GameClientDisconnected::clicked_exit_game, boost::ref(*this))); |
264 | + |
265 | + // Add all AI types |
266 | + for (const auto* impl : ComputerPlayer::get_implementations()) { |
267 | + type_dropdown_.add(impl->descname, |
268 | + impl->name, |
269 | + g_gr->images().get(impl->icon_filename), false, |
270 | + /** TRANSLATORS: Dropdown selection. Parameter is the name of the AI that will be used as replacement for a disconnected player */ |
271 | + (boost::format(_("Replace player with %s")) % impl->descname).str()); |
272 | + } |
273 | + |
274 | + // Set default mode to normal AI |
275 | + type_dropdown_.select(DefaultAI::normal_impl.name.c_str()); |
276 | + |
277 | + if (get_usedefaultpos()) { |
278 | + center_to_parent(); |
279 | + } |
280 | +} |
281 | + |
282 | +void GameClientDisconnected::die() { |
283 | + |
284 | + if (host_->forced_pause()) { |
285 | + host_->end_forced_pause(); |
286 | + } |
287 | + if (is_visible()) { |
288 | + // Dialog aborted, default to the old behavior and add a normal AI |
289 | + set_ai(DefaultAI::normal_impl.name); |
290 | + } |
291 | + UI::UniqueWindow::die(); |
292 | +} |
293 | + |
294 | +void GameClientDisconnected::clicked_continue() { |
295 | + assert(type_dropdown_.has_selection()); |
296 | + |
297 | + const std::string selection = type_dropdown_.get_selected(); |
298 | + assert(selection != ""); |
299 | + |
300 | + set_ai(selection); |
301 | + // Visibility works as a hint that the window was closed by a button click |
302 | + set_visible(false); |
303 | + |
304 | + die(); |
305 | +} |
306 | + |
307 | +void GameClientDisconnected::clicked_exit_game() { |
308 | + if (SDL_GetModState() & KMOD_CTRL) { |
309 | + igb_->end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack); |
310 | + } else { |
311 | + GameExitConfirmBox *gecb = new GameExitConfirmBox(*get_parent(), *igb_); |
312 | + gecb->cancel.connect( |
313 | + boost::bind(&GameClientDisconnected::exit_game_aborted, |
314 | + boost::ref(*this), gecb)); |
315 | + |
316 | + set_visible(false); |
317 | + } |
318 | +} |
319 | + |
320 | +void GameClientDisconnected::exit_game_aborted(Panel *dialog) { |
321 | + // Make parent window visible again so player can use another option |
322 | + set_visible(true); |
323 | + // Make panel (that is: the dialog box) invisible to avoid both being visible for a moment |
324 | + dialog->set_visible(false); |
325 | +} |
326 | + |
327 | +void GameClientDisconnected::set_ai(const std::string& ai) { |
328 | + const std::string ai_descr = ComputerPlayer::get_implementation(ai)->descname; |
329 | + for (size_t i = 0; i < host_->settings().players.size(); i++) { |
330 | + if (host_->settings().players.at(i).state != PlayerSettings::State::kOpen |
331 | + || !igb_->game().get_player(i + 1)->get_ai().empty()) { |
332 | + continue; |
333 | + } |
334 | + host_->replace_client_with_ai(i, ai); |
335 | + } |
336 | +} |
337 | |
338 | === added file 'src/wui/game_client_disconnected.h' |
339 | --- src/wui/game_client_disconnected.h 1970-01-01 00:00:00 +0000 |
340 | +++ src/wui/game_client_disconnected.h 2018-09-14 08:20:24 +0000 |
341 | @@ -0,0 +1,62 @@ |
342 | +/* |
343 | + * Copyright (C) 2002-2018 by the Widelands Development Team |
344 | + * |
345 | + * This program is free software; you can redistribute it and/or |
346 | + * modify it under the terms of the GNU General Public License |
347 | + * as published by the Free Software Foundation; either version 2 |
348 | + * of the License, or (at your option) any later version. |
349 | + * |
350 | + * This program is distributed in the hope that it will be useful, |
351 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
352 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
353 | + * GNU General Public License for more details. |
354 | + * |
355 | + * You should have received a copy of the GNU General Public License |
356 | + * along with this program; if not, write to the Free Software |
357 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
358 | + * |
359 | + */ |
360 | + |
361 | +#ifndef WL_WUI_GAME_CLIENT_DISCONNECTED_H |
362 | +#define WL_WUI_GAME_CLIENT_DISCONNECTED_H |
363 | + |
364 | +#include "ui_basic/box.h" |
365 | +#include "ui_basic/button.h" |
366 | +#include "ui_basic/dropdown.h" |
367 | +#include "ui_basic/multilinetextarea.h" |
368 | +#include "ui_basic/unique_window.h" |
369 | + |
370 | +class GameHost; |
371 | +class InteractiveGameBase; |
372 | + |
373 | +/** |
374 | + * Dialog that offers to replace a player with an AI or exit the game. |
375 | + * Even when the text only talks about a single player, actually all recently disconnected |
376 | + * players will be replaced by the taken choice. |
377 | + */ |
378 | +struct GameClientDisconnected : public UI::UniqueWindow { |
379 | + GameClientDisconnected(InteractiveGameBase*, |
380 | + UI::UniqueWindow::Registry&, |
381 | + GameHost*); |
382 | + |
383 | + void die() override; |
384 | + |
385 | +private: |
386 | + void clicked_continue(); |
387 | + void clicked_exit_game(); |
388 | + void exit_game_aborted(UI::Panel*); |
389 | + |
390 | + void set_ai(const std::string& ai); |
391 | + |
392 | + InteractiveGameBase* igb_; |
393 | + GameHost* host_; |
394 | + |
395 | + UI::Box box_; |
396 | + UI::Box box_h_; |
397 | + UI::MultilineTextarea text_; |
398 | + UI::Button continue_; |
399 | + UI::Dropdown<std::string> type_dropdown_; |
400 | + UI::Button exit_game_; |
401 | +}; |
402 | + |
403 | +#endif // end of include guard: WL_WUI_GAME_CLIENT_DISCONNECTED_H |
404 | |
405 | === added file 'src/wui/game_exit_confirm_box.cc' |
406 | --- src/wui/game_exit_confirm_box.cc 1970-01-01 00:00:00 +0000 |
407 | +++ src/wui/game_exit_confirm_box.cc 2018-09-14 08:20:24 +0000 |
408 | @@ -0,0 +1,43 @@ |
409 | +/* |
410 | + * Copyright (C) 2002-2018 by the Widelands Development Team |
411 | + * |
412 | + * This program is free software; you can redistribute it and/or |
413 | + * modify it under the terms of the GNU General Public License |
414 | + * as published by the Free Software Foundation; either version 2 |
415 | + * of the License, or (at your option) any later version. |
416 | + * |
417 | + * This program is distributed in the hope that it will be useful, |
418 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
419 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
420 | + * GNU General Public License for more details. |
421 | + * |
422 | + * You should have received a copy of the GNU General Public License |
423 | + * along with this program; if not, write to the Free Software |
424 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
425 | + * |
426 | + */ |
427 | + |
428 | +#include "wui/game_exit_confirm_box.h" |
429 | + |
430 | +#include "base/i18n.h" |
431 | + |
432 | +// TODO(GunChleoc): Arabic: Buttons need more height for Arabic |
433 | +GameExitConfirmBox::GameExitConfirmBox(UI::Panel& parent, InteractiveGameBase& gb) |
434 | + : UI::WLMessageBox(&parent, |
435 | + /** TRANSLATORS: Window label when "Exit game" has been pressed */ |
436 | + _("Exit Game Confirmation"), |
437 | + _("Are you sure you wish to exit this game?"), |
438 | + MBoxType::kOkCancel), |
439 | + igb_(gb) { |
440 | +} |
441 | + |
442 | +void GameExitConfirmBox::clicked_ok() { |
443 | + // Call method linked to ok button |
444 | + ok(); |
445 | + igb_.end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack); |
446 | +} |
447 | + |
448 | +void GameExitConfirmBox::clicked_back() { |
449 | + cancel(); |
450 | + die(); |
451 | +} |
452 | |
453 | === added file 'src/wui/game_exit_confirm_box.h' |
454 | --- src/wui/game_exit_confirm_box.h 1970-01-01 00:00:00 +0000 |
455 | +++ src/wui/game_exit_confirm_box.h 2018-09-14 08:20:24 +0000 |
456 | @@ -0,0 +1,41 @@ |
457 | +/* |
458 | + * Copyright (C) 2002-2018 by the Widelands Development Team |
459 | + * |
460 | + * This program is free software; you can redistribute it and/or |
461 | + * modify it under the terms of the GNU General Public License |
462 | + * as published by the Free Software Foundation; either version 2 |
463 | + * of the License, or (at your option) any later version. |
464 | + * |
465 | + * This program is distributed in the hope that it will be useful, |
466 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
467 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
468 | + * GNU General Public License for more details. |
469 | + * |
470 | + * You should have received a copy of the GNU General Public License |
471 | + * along with this program; if not, write to the Free Software |
472 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
473 | + * |
474 | + */ |
475 | + |
476 | +#ifndef WL_WUI_GAME_EXIT_CONFIRM_BOX_H |
477 | +#define WL_WUI_GAME_EXIT_CONFIRM_BOX_H |
478 | + |
479 | +#include "ui_basic/messagebox.h" |
480 | +#include "wui/interactive_gamebase.h" |
481 | + |
482 | +/** |
483 | + Simple ok/abort box asking whether the game really should be exited. |
484 | + */ |
485 | +class GameExitConfirmBox : public UI::WLMessageBox { |
486 | +public: |
487 | + GameExitConfirmBox(UI::Panel& parent, InteractiveGameBase& gb); |
488 | + |
489 | + void clicked_ok() override; |
490 | + |
491 | + void clicked_back() override; |
492 | + |
493 | +private: |
494 | + InteractiveGameBase& igb_; |
495 | +}; |
496 | + |
497 | +#endif // end of include guard: WL_WUI_GAME_EXIT_CONFIRM_BOX_H |
498 | |
499 | === modified file 'src/wui/game_options_menu.cc' |
500 | --- src/wui/game_options_menu.cc 2018-05-13 07:15:39 +0000 |
501 | +++ src/wui/game_options_menu.cc 2018-09-14 08:20:24 +0000 |
502 | @@ -27,6 +27,7 @@ |
503 | #include "base/i18n.h" |
504 | #include "graphic/graphic.h" |
505 | #include "sound/sound_handler.h" |
506 | +#include "wui/game_exit_confirm_box.h" |
507 | #include "wui/game_main_menu_save_game.h" |
508 | #include "wui/game_options_sound_menu.h" |
509 | #include "wui/unique_window_handler.h" |
510 | @@ -36,30 +37,6 @@ |
511 | #define vspacing 5 |
512 | #define vgap 3 |
513 | |
514 | -class GameOptionsMenuExitConfirmBox : public UI::WLMessageBox { |
515 | -public: |
516 | - // TODO(GunChleoc): Arabic: Buttons need more height for Arabic |
517 | - GameOptionsMenuExitConfirmBox(UI::Panel& parent, InteractiveGameBase& gb) |
518 | - : UI::WLMessageBox(&parent, |
519 | - /** TRANSLATORS: Window label when "Exit game" has been pressed */ |
520 | - _("Exit Game Confirmation"), |
521 | - _("Are you sure you wish to exit this game?"), |
522 | - MBoxType::kOkCancel), |
523 | - igb_(gb) { |
524 | - } |
525 | - |
526 | - void clicked_ok() override { |
527 | - igb_.end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack); |
528 | - } |
529 | - |
530 | - void clicked_back() override { |
531 | - die(); |
532 | - } |
533 | - |
534 | -private: |
535 | - InteractiveGameBase& igb_; |
536 | -}; |
537 | - |
538 | GameOptionsMenu::GameOptionsMenu(InteractiveGameBase& gb, |
539 | UI::UniqueWindow::Registry& registry, |
540 | InteractiveGameBase::GameMainMenuWindows& windows) |
541 | @@ -137,7 +114,7 @@ |
542 | if (SDL_GetModState() & KMOD_CTRL) { |
543 | igb_.end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack); |
544 | } else { |
545 | - new GameOptionsMenuExitConfirmBox(*get_parent(), igb_); |
546 | + new GameExitConfirmBox(*get_parent(), igb_); |
547 | die(); |
548 | } |
549 | } |
550 | |
551 | === modified file 'src/wui/interactive_gamebase.cc' |
552 | --- src/wui/interactive_gamebase.cc 2018-08-14 13:40:46 +0000 |
553 | +++ src/wui/interactive_gamebase.cc 2018-09-14 08:20:24 +0000 |
554 | @@ -34,9 +34,11 @@ |
555 | #include "logic/map.h" |
556 | #include "logic/map_objects/tribes/ship.h" |
557 | #include "logic/player.h" |
558 | +#include "network/gamehost.h" |
559 | #include "profile/profile.h" |
560 | #include "wui/constructionsitewindow.h" |
561 | #include "wui/dismantlesitewindow.h" |
562 | +#include "wui/game_client_disconnected.h" |
563 | #include "wui/game_summary.h" |
564 | #include "wui/militarysitewindow.h" |
565 | #include "wui/productionsitewindow.h" |
566 | @@ -284,3 +286,14 @@ |
567 | } |
568 | new GameSummaryScreen(this, &game_summary_); |
569 | } |
570 | + |
571 | +bool InteractiveGameBase::show_game_client_disconnected() { |
572 | + assert(is_a(GameHost, get_game()->game_controller())); |
573 | + if (!client_disconnected_.window) { |
574 | + if (upcast(GameHost, host, get_game()->game_controller())) { |
575 | + new GameClientDisconnected(this, client_disconnected_, host); |
576 | + return true; |
577 | + } |
578 | + } |
579 | + return false; |
580 | +} |
581 | |
582 | === modified file 'src/wui/interactive_gamebase.h' |
583 | --- src/wui/interactive_gamebase.h 2018-08-14 13:40:46 +0000 |
584 | +++ src/wui/interactive_gamebase.h 2018-09-14 08:20:24 +0000 |
585 | @@ -95,6 +95,8 @@ |
586 | } |
587 | |
588 | void show_game_summary(); |
589 | + /// For the game host. Show a window and ask the host player what to do with the tribe of the leaving client. |
590 | + bool show_game_client_disconnected(); |
591 | void postload() override; |
592 | void start() override; |
593 | |
594 | @@ -107,6 +109,7 @@ |
595 | PlayerType playertype_; |
596 | UI::UniqueWindow::Registry fieldaction_; |
597 | UI::UniqueWindow::Registry game_summary_; |
598 | + UI::UniqueWindow::Registry client_disconnected_; |
599 | UI::Button* toggle_buildhelp_; |
600 | UI::Button* reset_zoom_; |
601 |
Continuous integration builds have changed state:
Travis build 3921. State: passed. Details: https:/ /travis- ci.org/ widelands/ widelands/ builds/ 426390888. /ci.appveyor. com/project/ widelands- dev/widelands/ build/_ widelands_ dev_widelands_ bug_1434875_ net_client_ disconnect- 3719.
Appveyor build 3719. State: failed. Details: https:/