Merge lp:~widelands-dev/widelands/refactor_gamehost into lp:widelands
- refactor_gamehost
- Merge into trunk
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 |
Related bugs: |
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.
GunChleoc (gunchleoc) wrote : | # |
Added some comments with nits. Not tested yet.
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 5285. State: passed. Details: https:/
Appveyor build 5060. State: success. Details: https:/
GunChleoc (gunchleoc) wrote : | # |
You just asked for a review. See my comment above.
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.
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_
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
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 |
Continuous integration builds have changed state:
Travis build 5271. State: passed. Details: https:/ /travis- ci.org/ widelands/ widelands/ builds/ 560555689. /ci.appveyor. com/project/ widelands- dev/widelands/ build/_ widelands_ dev_widelands_ refactor_ gamehost- 5047.
Appveyor build 5047. State: failed. Details: https:/