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

Proposed by Klaus Halfmann
Status: Work in progress
Proposed branch: lp:~widelands-dev/widelands/refactor_gamehost
Merge into: lp:widelands
Diff against target: 849 lines (+307/-297)
2 files modified
src/network/gamehost.cc (+283/-295)
src/network/gamehost.h (+24/-2)
To merge this branch: bzr merge lp:~widelands-dev/widelands/refactor_gamehost
Reviewer Review Type Date Requested Status
Klaus Halfmann Needs Fixing
Review via email: mp+370320@code.launchpad.net

Commit message

Refactoring of gamehost.cc for better readability.

Description of the change

Refactoring of gamehost.cc for better readability,
should be completly compatible with trunk.

Please contact me, so we can do some testing vs. trunk.

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

Continuous integration builds have changed state:

Travis build 5271. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/560555689.
Appveyor build 5047. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_refactor_gamehost-5047.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Added some comments with nits. Not tested yet.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 5285. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/564564637.
Appveyor build 5060. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_refactor_gamehost-5060.

Revision history for this message
GunChleoc (gunchleoc) wrote :

You just asked for a review. See my comment above.

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

We must check this branch in the lobby.
As of some i/j confusion some message amy be wrong now.

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

Looks like I must check this with a debugger,
get his wheh joining a netwok game in trunk

Assertion failed: (clients_.at(id).state_ == Client::State::kConnected), function try_receive, file ../src/network/nethostproxy.cc, line 76.

review: Needs Fixing
Revision history for this message
GunChleoc (gunchleoc) wrote :

LAN or Internet game?

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

Internat game trunk as host this branch joining,
I get an assert about some missing image, too.
No idea where this cames from.
Maybe today I can throw some more time at the Problem.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/network/gamehost.cc'
2--- src/network/gamehost.cc 2019-09-05 20:04:47 +0000
3+++ src/network/gamehost.cc 2019-09-07 10:23:32 +0000
4@@ -902,7 +902,8 @@
5 }
6
7 /**
8- * If the host sends a chat message with formation /kick <name> <reason>
9+ * If the host sends a chat message with formation /kick <name> <reason>.
10+ *
11 * This function will handle this command and try to kick the user.
12 */
13 void GameHost::kick_user(uint32_t client, const std::string& reason) {
14@@ -979,18 +980,22 @@
15 return false;
16
17 // if there is one client that is currently receiving a file, we can not launch.
18+
19+ const std::vector<UserSettings> &users = d->settings.users;
20+
21 for (std::vector<Client>::iterator j = d->clients.begin(); j != d->clients.end(); ++j) {
22- if (j->usernum == -1) {
23+ const int usernum = j->usernum;
24+ if (usernum == -1) {
25 return false;
26 }
27- if (!d->settings.users[j->usernum].ready) {
28+ if (users[usernum].ready) {
29 return false;
30 }
31 }
32
33 // all players must be connected to a controller (human/ai) or be closed.
34 // but not all should be closed!
35- bool one_not_closed = false;
36+ bool one_not_closed = false; // TODO(k.halfmann): check this logic
37 for (PlayerSettings& setting : d->settings.players) {
38 if (setting.state != PlayerSettings::State::kClosed)
39 one_not_closed = true;
40@@ -1010,14 +1015,15 @@
41
42 std::vector<PlayerSettings>::size_type oldplayers = d->settings.players.size();
43
44- SendPacket packet;
45-
46 // Care about the host
47 if (static_cast<int32_t>(maxplayers) <= d->settings.playernum &&
48 d->settings.playernum != UserSettings::none()) {
49 set_player_number(UserSettings::none());
50 }
51
52+ SendPacket packet;
53+
54+ // Drop players not matching map any longer
55 while (oldplayers > maxplayers) {
56 --oldplayers;
57 for (uint16_t i = 1; i < d->settings.users.size(); ++i)
58@@ -1032,16 +1038,13 @@
59 d->clients.at(j).playernum = UserSettings::none();
60
61 // Broadcast change
62- packet.reset();
63- packet.unsigned_8(NETCMD_SETTING_USER);
64- packet.unsigned_32(i);
65- write_setting_user(packet, i);
66- broadcast(packet);
67+ broadcast_setting_user(packet, i);
68 }
69 }
70
71 d->settings.players.resize(maxplayers);
72
73+ // Open slots for new players found on the map.
74 while (oldplayers < maxplayers) {
75 PlayerSettings& player = d->settings.players.at(oldplayers);
76 player.state = PlayerSettings::State::kOpen;
77@@ -1109,9 +1112,12 @@
78 }
79 }
80
81+// TODO(k.halfmann): refactor this
82 void GameHost::set_player_state(uint8_t const number,
83 PlayerSettings::State const state,
84 bool const host) {
85+
86+ // ignore player numbers out of range
87 if (number >= d->settings.players.size())
88 return;
89
90@@ -1121,9 +1127,9 @@
91 return;
92
93 if (player.state == PlayerSettings::State::kHuman) {
94- // 0 is host and has no client
95- if (d->settings.users.at(0).position == number) {
96- d->settings.users.at(0).position = UserSettings::none();
97+ // kSpectatorPlayerNum has no client
98+ if (d->settings.users.at(kSpectatorPlayerNum).position == number) {
99+ d->settings.users.at(kSpectatorPlayerNum).position = UserSettings::none();
100 d->settings.playernum = UserSettings::none();
101 }
102 for (uint8_t i = 1; i < d->settings.users.size(); ++i) {
103@@ -1183,11 +1189,7 @@
104
105 // Broadcast change to player
106 SendPacket packet;
107- packet.reset();
108- packet.unsigned_8(NETCMD_SETTING_PLAYER);
109- packet.unsigned_8(number);
110- write_setting_player(packet, number);
111- broadcast(packet);
112+ broadcast_setting_player(packet, number);
113
114 // Let clients know whether their slot has changed
115 packet.reset();
116@@ -1204,6 +1206,7 @@
117
118 PlayerSettings& player = d->settings.players.at(number);
119
120+ // TODDO(k.halfmann): check this logic, will tribe "survive" een when random is selected?
121 if (player.tribe == tribe && player.random_tribe == random_tribe)
122 return;
123
124@@ -1224,11 +1227,8 @@
125
126 // broadcast changes
127 SendPacket packet;
128- packet.unsigned_8(NETCMD_SETTING_PLAYER);
129- packet.unsigned_8(number);
130- write_setting_player(packet, number);
131- broadcast(packet);
132- return;
133+ broadcast_setting_player(packet, number);
134+ return; // TODO(k.halfmann): check this logic
135 }
136 }
137 log("Player %u attempted to change to tribe %s; not a valid tribe\n", number, tribe.c_str());
138@@ -1250,10 +1250,7 @@
139
140 // broadcast changes
141 SendPacket packet;
142- packet.unsigned_8(NETCMD_SETTING_PLAYER);
143- packet.unsigned_8(number);
144- write_setting_player(packet, number);
145- broadcast(packet);
146+ broadcast_setting_player(packet, number);
147 return;
148 } else
149 log("Attempted to change to out-of-range initialization index %u "
150@@ -1275,10 +1272,7 @@
151
152 // Broadcast changes
153 SendPacket packet;
154- packet.unsigned_8(NETCMD_SETTING_PLAYER);
155- packet.unsigned_8(number);
156- write_setting_player(packet, number);
157- broadcast(packet);
158+ broadcast_setting_player(packet, number);
159 }
160
161 void GameHost::set_player_name(uint8_t const number, const std::string& name) {
162@@ -1294,10 +1288,7 @@
163
164 // Broadcast changes
165 SendPacket packet;
166- packet.unsigned_8(NETCMD_SETTING_PLAYER);
167- packet.unsigned_8(number);
168- write_setting_player(packet, number);
169- broadcast(packet);
170+ broadcast_setting_player(packet, number);
171 }
172
173 void GameHost::set_player_closeable(uint8_t const number, bool closeable) {
174@@ -1333,10 +1324,7 @@
175
176 // Broadcast changes
177 SendPacket packet;
178- packet.unsigned_8(NETCMD_SETTING_PLAYER);
179- packet.unsigned_8(number);
180- write_setting_player(packet, number);
181- broadcast(packet);
182+ broadcast_setting_player(packet, number);
183 }
184
185 void GameHost::set_player(uint8_t const number, const PlayerSettings& ps) {
186@@ -1348,10 +1336,7 @@
187
188 // Broadcast changes
189 SendPacket packet;
190- packet.unsigned_8(NETCMD_SETTING_PLAYER);
191- packet.unsigned_8(number);
192- write_setting_player(packet, number);
193- broadcast(packet);
194+ broadcast_setting_player(packet, number);
195 }
196
197 void GameHost::set_player_number(uint8_t const number) {
198@@ -1422,10 +1407,7 @@
199
200 // Broadcast the user changes to everybody
201 SendPacket packet;
202- packet.unsigned_8(NETCMD_SETTING_USER);
203- packet.unsigned_32(user);
204- write_setting_user(packet, user);
205- broadcast(packet);
206+ broadcast_setting_user(packet, user);
207 }
208
209 void GameHost::set_player_team(uint8_t number, Widelands::TeamNumber team) {
210@@ -1435,10 +1417,7 @@
211
212 // Broadcast changes
213 SendPacket packet;
214- packet.unsigned_8(NETCMD_SETTING_PLAYER);
215- packet.unsigned_8(number);
216- write_setting_player(packet, number);
217- broadcast(packet);
218+ broadcast_setting_player(packet, number);
219 }
220
221 void GameHost::set_multiplayer_game_settings() {
222@@ -1508,6 +1487,14 @@
223 Notifications::publish(NoteGameSettings(NoteGameSettings::Action::kPlayer, number));
224 }
225
226+void GameHost::broadcast_setting_player(SendPacket& packet, uint8_t const number) {
227+ packet.reset();
228+ packet.unsigned_8(NETCMD_SETTING_PLAYER);
229+ packet.unsigned_8(number);
230+ write_setting_player(packet, number);
231+ broadcast(packet);
232+}
233+
234 void GameHost::write_setting_all_players(SendPacket& packet) {
235 packet.unsigned_8(d->settings.players.size());
236 for (uint8_t i = 0; i < d->settings.players.size(); ++i) {
237@@ -1525,6 +1512,14 @@
238 NoteGameSettings::Action::kUser, d->settings.users.at(number).position, number));
239 }
240
241+void GameHost::broadcast_setting_user(SendPacket& packet, uint32_t const number) {
242+ packet.reset();
243+ packet.unsigned_8(NETCMD_SETTING_USER);
244+ packet.unsigned_32(number);
245+ write_setting_user(packet, number);
246+ broadcast(packet);
247+}
248+
249 void GameHost::write_setting_all_users(SendPacket& packet) {
250 packet.unsigned_8(d->settings.users.size());
251 for (uint32_t i = 0; i < d->settings.users.size(); ++i)
252@@ -1692,11 +1687,7 @@
253 d->net->send(client.sock_id, packet);
254
255 // Broadcast new information about the player to everybody
256- packet.reset();
257- packet.unsigned_8(NETCMD_SETTING_USER);
258- packet.unsigned_32(client.usernum);
259- write_setting_user(packet, client.usernum);
260- broadcast(packet);
261+ broadcast_setting_user(packet, client.usernum);
262
263 // Check if there is an unoccupied player left and if, assign.
264 for (uint8_t i = 0; i < d->settings.players.size(); ++i)
265@@ -2025,6 +2016,171 @@
266 reaper();
267 }
268
269+void GameHost::handle_disconnect(uint32_t const client_num, RecvPacket& r) {
270+ uint8_t number = r.unsigned_8();
271+ std::string reason = r.string();
272+ if (number == 1) {
273+ disconnect_client(client_num, reason, false);
274+ } else {
275+ std::string arg = r.string();
276+ disconnect_client(client_num, reason, false, arg);
277+ }
278+ return;
279+}
280+
281+void GameHost::handle_ping(Client& client) {
282+ log("[Host]: Received ping from metaserver.\n");
283+ // Send PING back
284+ SendPacket packet;
285+ packet.unsigned_8(NETCMD_METASERVER_PING);
286+ d->net->send(client.sock_id, packet);
287+
288+ // Remove metaserver from list of clients
289+ client.playernum = UserSettings::not_connected();
290+ d->net->close(client.sock_id);
291+ client.sock_id = 0;
292+ return;
293+}
294+
295+/** Wait for NETCMD_HELLO and handle unexpected other commands */
296+void GameHost::handle_hello(uint32_t const client_num, uint8_t const cmd, Client& client, RecvPacket& r) {
297+ // Now we wait for the client to say Hi in the right language,
298+ // unless the game has already started
299+ if (d->game) {
300+ throw DisconnectException("GAME_ALREADY_STARTED");
301+ }
302+ if (cmd != NETCMD_HELLO) {
303+ throw ProtocolException(cmd);
304+ }
305+ uint8_t version = r.unsigned_8();
306+ if (version != NETWORK_PROTOCOL_VERSION)
307+ throw DisconnectException("DIFFERENT_PROTOCOL_VERS");
308+
309+ std::string clientname = r.string();
310+ client.build_id = r.string();
311+
312+ welcome_client(client_num, clientname);
313+ return;
314+}
315+
316+void GameHost::handle_changetribe(Client& client, RecvPacket& r) {
317+ // Do not be harsh about packets of this type arriving out of order -
318+ // the client might just have had bad luck with the timing.
319+ if (!d->game) {
320+ uint8_t num = r.unsigned_8();
321+ if (num != client.playernum) {
322+ throw DisconnectException("NO_ACCESS_TO_PLAYER");
323+ }
324+ std::string tribe = r.string();
325+ bool random_tribe = r.unsigned_8() == 1;
326+ set_player_tribe(num, tribe, random_tribe);
327+ }
328+}
329+
330+/** Handle changed sharing of clients by users */
331+void GameHost::handle_changeshared(Client& client, RecvPacket& r) {
332+ // Do not be harsh about packets of this type arriving out of order -
333+ // the client might just have had bad luck with the timing.
334+ if (!d->game) {
335+ uint8_t num = r.unsigned_8();
336+ if (num != client.playernum)
337+ throw DisconnectException("NO_ACCESS_TO_PLAYER");
338+ set_player_shared(num, r.unsigned_8());
339+ }
340+}
341+
342+void GameHost::handle_changeteam(Client& client, RecvPacket& r) {
343+ if (!d->game) {
344+ uint8_t num = r.unsigned_8();
345+ if (num != client.playernum)
346+ throw DisconnectException("NO_ACCESS_TO_PLAYER");
347+ set_player_team(num, r.unsigned_8());
348+ }
349+}
350+
351+void GameHost::handle_changeinit(Client& client, RecvPacket& r) {
352+ if (!d->game) {
353+ // TODO(GunChleoc): For some nebulous reason, we don't receive the num that the client is
354+ // sending when a player changes slot. So, keeping the access to the client off for now.
355+ // Would be nice to have though.
356+ uint8_t num = r.unsigned_8();
357+ if (num != client.playernum)
358+ throw DisconnectException("NO_ACCESS_TO_PLAYER");
359+ set_player_init(num, r.unsigned_8());
360+ }
361+}
362+
363+void GameHost::handle_changeposition(Client& client, RecvPacket& r) {
364+ if (!d->game) {
365+ uint8_t const pos = r.unsigned_8();
366+ switch_to_player(client.usernum, pos);
367+ }
368+}
369+
370+void GameHost::handle_nettime(uint32_t const client_num, RecvPacket& r) {
371+ if (!d->game)
372+ throw DisconnectException("TIME_SENT_NOT_READY");
373+ receive_client_time(client_num, r.signed_32());
374+}
375+
376+void GameHost::handle_playercommmand(uint32_t const client_num, Client& client, RecvPacket& r) {
377+ if (!d->game)
378+ throw DisconnectException("PLAYERCMD_WO_GAME");
379+ int32_t time = r.signed_32();
380+ Widelands::PlayerCommand* plcmd = Widelands::PlayerCommand::deserialize(r);
381+ log("[Host]: Client %u (%u) sent player command %u for %u, time = %i\n", client_num, client.playernum,
382+ static_cast<unsigned int>(plcmd->id()), plcmd->sender(), time);
383+ receive_client_time(client_num, time);
384+ if (plcmd->sender() != client.playernum + 1)
385+ throw DisconnectException("PLAYERCMD_FOR_OTHER");
386+ send_player_command(plcmd);
387+}
388+
389+void GameHost::handle_syncreport(uint32_t const client_num, Client& client, RecvPacket& r) {
390+ if (!d->game || !d->syncreport_pending || client.syncreport_arrived) {
391+ throw DisconnectException("UNEXPECTED_SYNC_REP");
392+ }
393+ int32_t time = r.signed_32();
394+ r.data(client.syncreport.data, 16);
395+ client.syncreport_arrived = true;
396+ receive_client_time(client_num, time);
397+ check_sync_reports();
398+}
399+
400+void GameHost::handle_chat(Client& client, RecvPacket& r) {
401+ ChatMessage c(r.string());
402+ c.playern = d->settings.users.at(client.usernum).position;
403+ c.sender = d->settings.users.at(client.usernum).name;
404+ if (c.msg.size() && *c.msg.begin() == '@') {
405+ // Personal message
406+ std::string::size_type const space = c.msg.find(' ');
407+ if (space >= c.msg.size() - 1)
408+ return; // No Message after '@<User>'
409+ c.recipient = c.msg.substr(1, space - 1);
410+ c.msg = c.msg.substr(space + 1);
411+ }
412+ send(c);
413+}
414+
415+/** Take care of change of game speed PAUSE, 1x 2x 3x .... */
416+void GameHost::handle_speed(Client& client, RecvPacket& r) {
417+ client.desiredspeed = r.unsigned_16();
418+ update_network_speed();
419+}
420+
421+/** a new file should be uploaded to all players */
422+void GameHost::handle_new_file(Client& client) {
423+ if (!file_) // Do we have a file for sending?
424+ throw DisconnectException("REQUEST_OF_N_E_FILE");
425+ send_system_message_code(
426+ "STARTED_SENDING_FILE", file_->filename, d->settings.users.at(client.usernum).name);
427+ send_file_part(client.sock_id, 0);
428+ // Remember client as "currently receiving file"
429+ d->settings.users[client.usernum].ready = false;
430+ SendPacket packet;
431+ broadcast_setting_user(packet, client.usernum);
432+}
433+
434 /**
435 * Handle a single received packet.
436 *
437@@ -2033,246 +2189,82 @@
438 * \param i the client number
439 * \param r the received packet
440 */
441-void GameHost::handle_packet(uint32_t const i, RecvPacket& r) {
442- Client& client = d->clients.at(i);
443+void GameHost::handle_packet(uint32_t const client_num, RecvPacket& r) {
444+ Client& client = d->clients.at(client_num);
445 uint8_t const cmd = r.unsigned_8();
446
447 if (cmd == NETCMD_DISCONNECT) {
448- uint8_t number = r.unsigned_8();
449- std::string reason = r.string();
450- if (number == 1)
451- disconnect_client(i, reason, false);
452- else {
453- std::string arg = r.string();
454- disconnect_client(i, reason, false, arg);
455- }
456- return;
457+ return handle_disconnect(client_num, r);
458 }
459
460 if (client.playernum == UserSettings::not_connected()) {
461 if (cmd == NETCMD_METASERVER_PING) {
462- log("[Host]: Received ping from metaserver.\n");
463- // Send PING back
464- SendPacket packet;
465- packet.unsigned_8(NETCMD_METASERVER_PING);
466- d->net->send(client.sock_id, packet);
467-
468- // Remove metaserver from list of clients
469- client.playernum = UserSettings::not_connected();
470- d->net->close(client.sock_id);
471- client.sock_id = 0;
472- return;
473+ return handle_ping(client);
474 }
475-
476 // Now we wait for the client to say Hi in the right language,
477- // unless the game has already started
478- if (d->game)
479- throw DisconnectException("GAME_ALREADY_STARTED");
480-
481- if (cmd != NETCMD_HELLO)
482- throw ProtocolException(cmd);
483-
484- uint8_t version = r.unsigned_8();
485- if (version != NETWORK_PROTOCOL_VERSION)
486- throw DisconnectException("DIFFERENT_PROTOCOL_VERS");
487-
488- std::string clientname = r.string();
489- client.build_id = r.string();
490-
491- welcome_client(i, clientname);
492- return;
493+ return handle_hello(client_num, cmd, client, r);
494 }
495
496 switch (cmd) {
497- case NETCMD_PONG:
498- log("[Host]: Client %u: got pong\n", i);
499- break;
500-
501- case NETCMD_SETTING_MAP:
502- if (!d->game) {
503- throw DisconnectException("NO_ACCESS_TO_SERVER");
504- }
505- break;
506-
507- case NETCMD_SETTING_CHANGETRIBE:
508- // Do not be harsh about packets of this type arriving out of order -
509- // the client might just have had bad luck with the timing.
510- if (!d->game) {
511- uint8_t num = r.unsigned_8();
512- if (num != client.playernum)
513- throw DisconnectException("NO_ACCESS_TO_PLAYER");
514- std::string tribe = r.string();
515- bool random_tribe = r.unsigned_8() == 1;
516- set_player_tribe(num, tribe, random_tribe);
517- }
518- break;
519-
520- case NETCMD_SETTING_CHANGESHARED:
521- // Do not be harsh about packets of this type arriving out of order -
522- // the client might just have had bad luck with the timing.
523- if (!d->game) {
524- uint8_t num = r.unsigned_8();
525- if (num != client.playernum)
526- throw DisconnectException("NO_ACCESS_TO_PLAYER");
527- set_player_shared(num, r.unsigned_8());
528- }
529- break;
530-
531- case NETCMD_SETTING_CHANGETEAM:
532- if (!d->game) {
533- uint8_t num = r.unsigned_8();
534- if (num != client.playernum)
535- throw DisconnectException("NO_ACCESS_TO_PLAYER");
536- set_player_team(num, r.unsigned_8());
537- }
538- break;
539-
540- case NETCMD_SETTING_CHANGEINIT:
541- if (!d->game) {
542- // TODO(GunChleoc): For some nebulous reason, we don't receive the num that the client is
543- // sending when a player changes slot. So, keeping the access to the client off for now.
544- // Would be nice to have though.
545- uint8_t num = r.unsigned_8();
546- if (num != client.playernum)
547- throw DisconnectException("NO_ACCESS_TO_PLAYER");
548- set_player_init(num, r.unsigned_8());
549- }
550- break;
551-
552- case NETCMD_SETTING_CHANGEPOSITION:
553- if (!d->game) {
554- uint8_t const pos = r.unsigned_8();
555- switch_to_player(client.usernum, pos);
556- }
557- break;
558-
559- case NETCMD_SETTING_PLAYER:
560- if (!d->game) {
561- throw DisconnectException("NO_ACCESS_TO_SERVER");
562- }
563- break;
564-
565- case NETCMD_WIN_CONDITION:
566- if (!d->game) {
567- throw DisconnectException("NO_ACCESS_TO_SERVER");
568- }
569- break;
570-
571- case NETCMD_PEACEFUL_MODE:
572- if (!d->game) {
573- throw DisconnectException("NO_ACCESS_TO_SERVER");
574- }
575- break;
576-
577- case NETCMD_LAUNCH:
578- if (!d->game) {
579- throw DisconnectException("NO_ACCESS_TO_SERVER");
580- }
581- break;
582-
583- case NETCMD_TIME:
584- if (!d->game)
585- throw DisconnectException("TIME_SENT_NOT_READY");
586- receive_client_time(i, r.signed_32());
587- break;
588-
589- case NETCMD_PLAYERCOMMAND: {
590- if (!d->game)
591- throw DisconnectException("PLAYERCMD_WO_GAME");
592- int32_t time = r.signed_32();
593- Widelands::PlayerCommand* plcmd = Widelands::PlayerCommand::deserialize(r);
594- log("[Host]: Client %u (%u) sent player command %u for %u, time = %i\n", i, client.playernum,
595- static_cast<unsigned int>(plcmd->id()), plcmd->sender(), time);
596- receive_client_time(i, time);
597- if (plcmd->sender() != client.playernum + 1)
598- throw DisconnectException("PLAYERCMD_FOR_OTHER");
599- send_player_command(plcmd);
600- } break;
601-
602- case NETCMD_SYNCREPORT: {
603- if (!d->game || !d->syncreport_pending || client.syncreport_arrived)
604- throw DisconnectException("UNEXPECTED_SYNC_REP");
605- int32_t time = r.signed_32();
606- r.data(client.syncreport.data, 16);
607- client.syncreport_arrived = true;
608- receive_client_time(i, time);
609- check_sync_reports();
610- break;
611- }
612-
613- case NETCMD_CHAT: {
614- ChatMessage c(r.string());
615- c.playern = d->settings.users.at(client.usernum).position;
616- c.sender = d->settings.users.at(client.usernum).name;
617- if (c.msg.size() && *c.msg.begin() == '@') {
618- // Personal message
619- std::string::size_type const space = c.msg.find(' ');
620- if (space >= c.msg.size() - 1)
621- break;
622- c.recipient = c.msg.substr(1, space - 1);
623- c.msg = c.msg.substr(space + 1);
624- }
625- send(c);
626- break;
627- }
628-
629- case NETCMD_SETSPEED: {
630- client.desiredspeed = r.unsigned_16();
631- update_network_speed();
632- break;
633- }
634-
635- case NETCMD_NEW_FILE_AVAILABLE: {
636- if (!file_) // Do we have a file for sending
637- throw DisconnectException("REQUEST_OF_N_E_FILE");
638+ case NETCMD_PONG:
639+ log("[Host]: Client %u: got pong\n", client_num);
640+ break;
641+
642+ case NETCMD_SETTING_CHANGETRIBE: return handle_changetribe(client, r);
643+ case NETCMD_SETTING_CHANGESHARED: return handle_changeshared(client, r);
644+ case NETCMD_SETTING_CHANGETEAM: return handle_changeteam(client, r);
645+ case NETCMD_SETTING_CHANGEINIT: return handle_changeinit(client, r);
646+ case NETCMD_SETTING_CHANGEPOSITION: return handle_changeposition(client, r);
647+ case NETCMD_TIME: return handle_nettime(client_num, r);
648+ case NETCMD_PLAYERCOMMAND: return handle_playercommmand(client_num, client, r);
649+ case NETCMD_SYNCREPORT: return handle_syncreport(client_num, client, r);
650+ case NETCMD_CHAT: return handle_chat(client, r);
651+ case NETCMD_SETSPEED: return handle_speed(client, r);
652+ case NETCMD_NEW_FILE_AVAILABLE: return handle_new_file(client);
653+ case NETCMD_FILE_PART: return handle_file_part(client, r);
654+
655+ case NETCMD_SETTING_MAP:
656+ case NETCMD_SETTING_PLAYER:
657+ case NETCMD_WIN_CONDITION:
658+ case NETCMD_PEACEFUL_MODE:
659+ case NETCMD_LAUNCH:
660+ if (!d->game) { // not expected whe game is in progress -> somethings wrong here
661+ throw DisconnectException("NO_ACCESS_TO_SERVER");
662+ }
663+ break;
664+
665+ default:
666+ throw ProtocolException(cmd);
667+ }
668+}
669+
670+/** Handle uploading part of a file */
671+void GameHost::handle_file_part(Client& client, RecvPacket& r) {
672+ if (!file_) // Do we have a file for sending
673+ throw DisconnectException("REQUEST_OF_N_E_FILE");
674+ uint32_t part = r.unsigned_32();
675+ std::string x = r.string();
676+ if (x != file_->md5sum) {
677+ log(
678+ "[Host]: File transfer checksum mismatch %s != %s\n", x.c_str(), file_->md5sum.c_str());
679+ return; // Surely the file was changed, so we cancel here.
680+ }
681+ if (part >= file_->parts.size())
682+ throw DisconnectException("REQUEST_OF_N_E_FILEPART");
683+ if (part == file_->parts.size() - 1) {
684 send_system_message_code(
685- "STARTED_SENDING_FILE", file_->filename, d->settings.users.at(client.usernum).name);
686- send_file_part(client.sock_id, 0);
687- // Remember client as "currently receiving file"
688- d->settings.users[client.usernum].ready = false;
689+ "COMPLETED_FILE_TRANSFER", file_->filename, d->settings.users.at(client.usernum).name);
690+ d->settings.users[client.usernum].ready = true;
691 SendPacket packet;
692- packet.unsigned_8(NETCMD_SETTING_USER);
693- packet.unsigned_32(client.usernum);
694- write_setting_user(packet, client.usernum);
695- broadcast(packet);
696- break;
697- }
698-
699- case NETCMD_FILE_PART: {
700- if (!file_) // Do we have a file for sending
701- throw DisconnectException("REQUEST_OF_N_E_FILE");
702- uint32_t part = r.unsigned_32();
703- std::string x = r.string();
704- if (x != file_->md5sum) {
705- log(
706- "[Host]: File transfer checksum mismatch %s != %s\n", x.c_str(), file_->md5sum.c_str());
707- return; // Surely the file was changed, so we cancel here.
708- }
709- if (part >= file_->parts.size())
710- throw DisconnectException("REQUEST_OF_N_E_FILEPART");
711- if (part == file_->parts.size() - 1) {
712- send_system_message_code(
713- "COMPLETED_FILE_TRANSFER", file_->filename, d->settings.users.at(client.usernum).name);
714- d->settings.users[client.usernum].ready = true;
715- SendPacket packet;
716- packet.unsigned_8(NETCMD_SETTING_USER);
717- packet.unsigned_32(client.usernum);
718- write_setting_user(packet, client.usernum);
719- broadcast(packet);
720- return;
721- }
722- ++part;
723- if (part % 100 == 0)
724- send_system_message_code("SENDING_FILE_PART",
725- (boost::format("%i/%i") % part % (file_->parts.size() + 1)).str(),
726- file_->filename, d->settings.users.at(client.usernum).name);
727- send_file_part(client.sock_id, part);
728- break;
729- }
730-
731- default:
732- throw ProtocolException(cmd);
733- }
734+ broadcast_setting_user(packet, client.usernum);
735+ return;
736+ }
737+ ++part;
738+ if (part % 100 == 0) // Show Progress message every 100th transfer
739+ send_system_message_code("SENDING_FILE_PART",
740+ (boost::format("%i/%i") % part % (file_->parts.size() + 1)).str(),
741+ file_->filename, d->settings.users.at(client.usernum).name);
742+ send_file_part(client.sock_id, part);
743 }
744
745 void GameHost::send_file_part(NetHostInterface::ConnectionId csock_id, uint32_t part) {
746@@ -2313,13 +2305,13 @@
747 // Don't replace player with AI, let host choose what to do
748 }
749
750-void GameHost::disconnect_client(uint32_t const number,
751+void GameHost::disconnect_client(uint32_t const client_number,
752 const std::string& reason,
753 bool const sendreason,
754 const std::string& arg) {
755- assert(number < d->clients.size());
756+ assert(client_number < d->clients.size());
757
758- Client& client = d->clients.at(number);
759+ Client& client = d->clients.at(client_number);
760
761 // If the client is linked to a player and it is the client that closes the connection
762 // and the game has already started ...
763@@ -2357,8 +2349,7 @@
764 disconnect_player_controller(position, d->settings.users.at(client.usernum).name);
765 }
766 // Do NOT reset the clients name in the corresponding UserSettings, that way we keep the name
767- // for the
768- // statistics.
769+ // for the statistics.
770 // d->settings.users.at(client.usernum).name = std::string();
771
772 // Broadcast the user changes to everybody
773@@ -2366,14 +2357,11 @@
774 "CLIENT_X_LEFT_GAME", d->settings.users.at(client.usernum).name, reason, arg);
775
776 SendPacket packet;
777- packet.unsigned_8(NETCMD_SETTING_USER);
778- packet.unsigned_32(client.usernum);
779- write_setting_user(packet, client.usernum);
780- broadcast(packet);
781- } else
782+ broadcast_setting_user(packet, client.usernum);
783+ } else {
784 send_system_message_code("UNKNOWN_LEFT_GAME", reason, arg);
785-
786- log("[Host]: disconnect_client(%u, %s, %s)\n", number, reason.c_str(), arg.c_str());
787+ }
788+ log("[Host]: disconnect_client(%u, %s, %s)\n", client_number, reason.c_str(), arg.c_str());
789
790 if (client.sock_id > 0) {
791 if (sendreason) {
792
793=== modified file 'src/network/gamehost.h'
794--- src/network/gamehost.h 2019-05-25 07:36:44 +0000
795+++ src/network/gamehost.h 2019-09-07 10:23:32 +0000
796@@ -41,6 +41,9 @@
797 * launch, as well as dealing with the actual network protocol.
798 */
799 struct GameHost : public GameController {
800+ /** playernumber 0 identifies the spectators */
801+ static constexpr uint8_t kSpectatorPlayerNum = 0;
802+
803 GameHost(const std::string& playername, bool internet = false);
804 ~GameHost() override;
805
806@@ -63,6 +66,7 @@
807
808 // Pregame-related stuff
809 const GameSettings& settings();
810+ /** return true in case all conditions for the game start are met */
811 bool can_launch();
812 void set_scenario(bool);
813 void set_map(const std::string& mapname,
814@@ -129,6 +133,22 @@
815 void init_computer_player(Widelands::PlayerNumber p);
816 void init_computer_players();
817
818+ void handle_disconnect(uint32_t client_num, RecvPacket& r);
819+ void handle_ping(Client& client);
820+ void handle_hello(uint32_t client_num, uint8_t cmd, Client& client, RecvPacket& r);
821+ void handle_changetribe(Client& client, RecvPacket& r);
822+ void handle_changeshared(Client& client, RecvPacket& r);
823+ void handle_changeteam(Client& client, RecvPacket& r);
824+ void handle_changeinit(Client& client, RecvPacket& r);
825+ void handle_changeposition(Client& client, RecvPacket& r);
826+ void handle_nettime(uint32_t client_num, RecvPacket& r);
827+ void handle_playercommmand(uint32_t client_num, Client& client, RecvPacket& r);
828+ void handle_syncreport(uint32_t client_num, Client& client, RecvPacket& r);
829+ void handle_chat(Client& client, RecvPacket& r);
830+ void handle_speed(Client& client, RecvPacket& r);
831+ void handle_new_file(Client& client);
832+ void handle_file_part(Client& client, RecvPacket& r);
833+
834 void handle_packet(uint32_t i, RecvPacket&);
835 void handle_network();
836 void send_file_part(NetHostInterface::ConnectionId client_sock_id, uint32_t part);
837@@ -145,9 +165,11 @@
838
839 void broadcast(SendPacket&);
840 void write_setting_map(SendPacket&);
841- void write_setting_player(SendPacket&, uint8_t number);
842+ void write_setting_player(SendPacket&, uint8_t number);
843+ void broadcast_setting_player(SendPacket&, uint8_t number);
844 void write_setting_all_players(SendPacket&);
845- void write_setting_user(SendPacket&, uint32_t number);
846+ void write_setting_user(SendPacket& packet, uint32_t number);
847+ void broadcast_setting_user(SendPacket& packet, uint32_t number);
848 void write_setting_all_users(SendPacket&);
849 bool write_map_transfer_info(SendPacket&, std::string);
850

Subscribers

People subscribed via source and target branches

to status/vote changes: