1 /*
2 * Copyright 2014, 2016 Peter Olsson
3 *
4 * This file is part of Brum Brum Rally.
5 *
6 * Brum Brum Rally is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Brum Brum Rally is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "Network.h"
21 #include "GameState.h"
22 #include "Settings.h"
23 #include "Track.h"
24 #include "StateManager.h"
25 #include "RaceState.h"
26 #include "NetworkBlankState.h"
27 #include "Track.h"
28 #include "Driver.h"
29 #include "ResultState.h"
30 #include "AIDriver.h"
31 #include "ErrorState.h"
32 #include "NetworkMenu.h"
33 #include "str.h"
34 #include <limits>
35 #include <algorithm>
36 #include <cassert>
37 #include <sstream>
38
39 extern const int GAME_WIDTH;
40
41 const Uint32 CONNECTION_TIMEOUT = 30000;
42 const Uint32 GAMEINFO_SEND_INTERVAL = 1000;
43 const Uint32 GAMEINFO_TIMEOUT = 3000;
44 const Uint32 CHAT_SEND_INTERVAL = 250;
45 const Uint32 PING_SEND_START = 20000;
46 const Uint32 PING_SEND_INTERVAL = 3000;
47 const Uint32 JOIN_TIMEOUT = 20000;
48 const Uint32 GAME_STATE_SEND_INTERVAL = 100;
49 const Uint32 GAME_TIMEOUT = 10000;
50 const Uint32 GAME_NO_CHAT_INTERVAL = 2000;
51 const Uint32 GAME_CHAT_INTERVAL = 100;
52
53 const Uint32 CHAT_MESSAGE_TIMEOUT = 8000;
54
55 const int NETWORK_STEP = 5;
56
Network()57 Network::Network()
58 : socket(0),
59 connectionsIt(connections.end()),
60 connectionType(NET_LOBBY),
61 gameState(),
62 lastChatMessage(0),
63 chatOn(true),
64 game(),
65 reservedCars(0),
66 joinStatus(),
67 newGameState(0),
68 gameStateId(0),
69 gameStateCount(0),
70 lastGameTimestamp(0),
71 lastGameSent(0),
72 newTrackInfoReady(false),
73 newTrackInfoCounter(0),
74 newTrackStateTick(0),
75 inputBuffer(),
76 raceTick(0),
77 lastSlowDown(0),
78 track(),
79 lastChatMessageDeliveredToGameOwner(0),
80 lastChatMessageRecivedFromGameOwner(0)
81 {
82 if (SDLNet_Init() < 0)
83 {
84 error = SDL_GetError();
85 }
86 }
87
~Network()88 Network::~Network()
89 {
90 quitGame();
91
92 SDLNet_UDP_Close(socket);
93 SDLNet_Quit();
94 }
95
step()96 void Network::step()
97 {
98 while (receive())
99 {
100 handleMessage(msg.read8(), msg.getPacket().address);
101 }
102
103 Uint32 now = SDL_GetTicks();
104
105 while (!chatBuffer.empty() && chatBuffer.back().timestamp + CHAT_MESSAGE_TIMEOUT <= now)
106 {
107 chatBuffer.pop_back();
108 }
109
110 if (!connections.empty())
111 {
112 if (connectionsIt == connections.end())
113 {
114 connectionsIt = connections.begin();
115 }
116
117 const IPaddress& address = connectionsIt->first;
118 Connection& connection = connectionsIt->second;
119
120 if (connection.lastRecive + CONNECTION_TIMEOUT <= now)
121 {
122 // Timeout.
123 onConnectionTimeout(address);
124 gameList.update(address, 0);
125 delete connection.gameInfo;
126 connections.erase(connectionsIt++);
127 }
128 else
129 {
130 if (connection.gameInfo && connection.lastRecive + GAMEINFO_TIMEOUT <= now)
131 {
132 gameList.update(address, 0);
133 delete connection.gameInfo;
134 connection.gameInfo = 0;
135 }
136
137 if (connectionType == NET_LOBBY)
138 {
139 if (connection.gameInfo == 0 &&
140 !chatBuffer.empty() &&
141 connection.lastChatMessageDelivered < lastChatMessage)
142 {
143 if (connection.lastSend + CHAT_SEND_INTERVAL <= now)
144 {
145 // Send unreceived message.
146 sendLobbyMessage(connection, address);
147 }
148 }
149 if (connection.lastSend + GAMEINFO_SEND_INTERVAL <= now)
150 {
151 // Request game info from game owners.
152 // This also helps avoid timeout.
153 // We send this message for all connections because
154 // we don't know if they have become a game owner
155 // without us notice.
156 sendLobbyMessage(connection, address);
157 }
158 }
159 else if (connectionType == NET_GAME_OWNER)
160 {
161 if (connection.lastRecive + PING_SEND_START <= now)
162 {
163 if (connection.lastSend + PING_SEND_INTERVAL <= now)
164 {
165 msg.reset();
166 msg.write8(MSG_PING);
167 msg.write32(now);
168 send(address);
169 connection.lastSend = SDL_GetTicks();
170 }
171 }
172 }
173 ++connectionsIt;
174 }
175 }
176
177 chat.update();
178
179 if (connectionType == NET_GAME_OWNER)
180 {
181 // Timeouts
182 std::map<IPaddress, GamePlayer>::iterator it;
183 for (it = gameClients.begin(); it != gameClients.end();)
184 {
185 GamePlayer& gp = it->second;
186 std::map<IPaddress, GamePlayer>::iterator tmp = it++;
187 if (gp.lastRecive + GAME_TIMEOUT <= now)
188 {
189 erasePlayer(tmp, "timeout");
190 }
191 }
192
193 std::map<IPaddress, JoinInProgress>::iterator jit;
194 for (jit = joinInProgress.begin(); jit != joinInProgress.end();)
195 {
196 JoinInProgress& jip = jit->second;
197 std::map<IPaddress, JoinInProgress>::iterator tmp = jit++;
198 if (jip.timeout <= now)
199 {
200 reservedCars &= ~jip.reservedCars;
201 reservedPlayers -= jip.reservedPlayers;
202 joinInProgress.erase(tmp);
203 }
204 }
205
206 // Send new state info.
207 if (lastGameSent + GAME_STATE_SEND_INTERVAL <= now)
208 {
209 std::map<IPaddress, GamePlayer>::iterator it;
210 for (it = gameClients.begin(); it != gameClients.end(); ++it)
211 {
212 GamePlayer& gp = it->second;
213 const IPaddress& address = it->first;
214
215 if (gp.gameStateId != gameStateId)
216 {
217 msg.reset();
218 if (gameStateId == NETWORK_GAME_STATE_RACE)
219 {
220 msg.write8(MSG_NEW_STATE_RACE);
221 msg.write32(now);
222 msg.write32(gameStateCount);
223 msg.write8(game.laps);
224 msg.write8(game.collisions);
225 map.write(msg);
226 msg.write8(raceCars.size());
227 for (std::size_t i = 0; i < raceCars.size(); ++i)
228 {
229 NetworkRaceCar& nrc = *raceCars[i];
230 msg.write8(nrc.car);
231 msg.write8(nrc.player == &gp ? nrc.driver : std::numeric_limits<Uint8>::max());
232 }
233 }
234 else if (gameStateId == NETWORK_GAME_STATE_TIMES ||
235 gameStateId == NETWORK_GAME_STATE_POINTS)
236 {
237 msg.write8(gameStateId == NETWORK_GAME_STATE_TIMES ? MSG_NEW_STATE_TIMES : MSG_NEW_STATE_POINTS);
238 msg.write32(now);
239 msg.write32(gameStateCount);
240 msg.write8(game.tracks);
241 msg.write8(game.track);
242 msg.write8(raceCars.size());
243
244 std::vector<NetworkRaceCar*>::iterator it;
245 for (it = raceCars.begin(); it != raceCars.end(); ++it)
246 {
247 NetworkRaceCar& car = **it;
248
249 msg.write8(car.car);
250 msg.writeString(car.name);
251 msg.write32(gameStateId == NETWORK_GAME_STATE_TIMES ? car.time : car.points);
252 }
253 }
254 else
255 {
256 // This should never happen!
257 assert("invalid game state id");
258 continue;
259 }
260 send(address);
261 }
262 }
263 lastGameSent = SDL_GetTicks();
264 }
265
266 // Send race state.
267 if (gameStateId == NETWORK_GAME_STATE_RACE && newTrackInfoReady)
268 {
269 std::map<IPaddress, GamePlayer>::iterator it;
270 for (it = gameClients.begin(); it != gameClients.end(); ++it)
271 {
272 GamePlayer& gp = it->second;
273 const IPaddress& address = it->first;
274
275 if (gp.gameStateId == gameStateId)
276 {
277 msg.reset();
278 msg.write8(MSG_RACE_STATE);
279 msg.write32(now);
280
281 msg.write8(track->getCarCount());
282 msg.write8(removedCars.size());
283 for (std::size_t i = removedCars.size() - 1; i < removedCars.size(); --i)
284 {
285 msg.write8(removedCars[i]);
286 }
287
288 msg.write32(raceTick);
289 Uint32 stateTick = std::max<Uint32>(gp.lastTick - gp.lastTick % NETWORK_STEP, newTrackStateTick - (TRACK_BUFFER_SIZE - 1) * NETWORK_STEP);
290 msg.write32(stateTick);
291 msg.write32(gp.ticksTooFast);
292 msg.write32(gp.lastTimestamp);
293
294 const TrackState& trackState = trackStateBuffer[(newTrackStateTick - stateTick) / NETWORK_STEP];
295 trackState.write(msg, raceCars.size());
296
297 for (Uint32 tick = stateTick; tick <= raceTick; ++tick)
298 {
299 msg.write32(inputBuffer[raceTick - tick]);
300 }
301
302 writeChatMessage(gp);
303
304 send(address);
305 }
306 }
307 newTrackInfoReady = false;
308 newTrackInfoCounter = 0;
309 }
310 else if (gameStateId == NETWORK_GAME_STATE_TIMES ||
311 gameStateId == NETWORK_GAME_STATE_POINTS)
312 {
313 for (it = gameClients.begin(); it != gameClients.end(); ++it)
314 {
315 GamePlayer& gp = it->second;
316 IPaddress address = it->first;
317 bool haveMessagesToSend = !chatBuffer.empty() && gp.lastChatMessageDelivered < lastChatMessage;
318
319 if (gp.lastSent + (haveMessagesToSend ? GAME_CHAT_INTERVAL : GAME_NO_CHAT_INTERVAL) <= now)
320 {
321 msg.reset();
322 msg.write8(MSG_GAME_CHAT_INFO);
323 msg.write32(now);
324 writeChatMessage(gp);
325 send(address);
326 gp.lastSent = SDL_GetTicks();
327 }
328 }
329 }
330 }
331 else if (connectionType == NET_GAME_PLAYER)
332 {
333 // Timeout
334 if (lastGameRecive + GAME_TIMEOUT <= now)
335 {
336 setNewGameState(new ErrorState("End of game", "The network game has timed out", new NetworkMenu(this)));
337 }
338 else if (newTrackInfoReady)
339 {
340 msg.write8(MSG_RACE_INPUT);
341 msg.write32(now);
342
343 writeChatMessage();
344
345 msg.write32(raceTick);
346 for (std::size_t i = 0; i < INPUT_BUFFER_SIZE; ++i)
347 {
348 msg.write32(inputBuffer[i]);
349 }
350
351 send(gameOwner);
352
353 newTrackInfoReady = false;
354 newTrackInfoCounter = 0;
355 }
356 else if (gameStateId == NETWORK_GAME_STATE_TIMES ||
357 gameStateId == NETWORK_GAME_STATE_POINTS)
358 {
359 bool haveMessagesToSend = !chatBuffer.empty() && lastChatMessageDeliveredToGameOwner < lastChatMessage;
360
361 if (lastGameSent + (haveMessagesToSend ? GAME_CHAT_INTERVAL : GAME_NO_CHAT_INTERVAL) <= now)
362 {
363 msg.write8(MSG_GAME_CHAT_ADD);
364 msg.write32(now);
365 writeChatMessage();
366 send(gameOwner);
367 lastGameSent = SDL_GetTicks();
368 }
369 }
370 }
371 }
372
updateTrack(bool noInput)373 void Network::updateTrack(bool noInput)
374 {
375 if (gameStateId != NETWORK_GAME_STATE_RACE)
376 {
377 return;
378 }
379
380 assert(track);
381
382 Uint32& prevInput = inputBuffer[0];
383 Uint32& input = inputBuffer.next();
384
385 // Copy previous input.
386 input = prevInput;
387
388 // Collect local input.
389 for (std::size_t i = 0; i < localCars.size(); ++i)
390 {
391 assert(i < localCars.size());
392 const NetworkRaceCar& car = localCars[i];
393
394 if (car.id >= 0 && car.human)
395 {
396 int carInput = noInput ? 0 : StateManager::getInstance().getDriver(car.driver)->drive(car.id, *track);
397 input = (input & ~(0xF << (4 * car.id))) | (carInput << (4 * car.id));
398 }
399 }
400
401 track->update(TRACK_TIME_STEP * 0.001, &input);
402 ++raceTick;
403
404 if (raceTick % NETWORK_STEP == 0)
405 {
406 if (connectionType == NET_GAME_OWNER)
407 {
408 TrackState& trackState = trackStateBuffer.next();
409 track->save(trackState);
410 newTrackStateTick = raceTick;
411 }
412 }
413 ++newTrackInfoCounter;
414 if (input != prevInput || newTrackInfoCounter >= NETWORK_STEP)
415 {
416 newTrackInfoReady = true;
417 }
418 }
419
setStatus(const std::string & str)420 void Network::setStatus(const std::string& str)
421 {
422 Surface s(str, BIG_FONT, 123456, TEXT_BORDER_COLOR);
423 statusRenderObject.setSurface(s);
424 statusRenderObject.moveTo(GAME_WIDTH - s.width() - 2, 3);
425 }
426
getError() const427 const std::string& Network::getError() const
428 {
429 return error;
430 }
431
handleMessage(Uint8 msgType,IPaddress address)432 void Network::handleMessage(Uint8 msgType, IPaddress address)
433 {
434 Uint32 timestamp = msg.read32();
435 Uint32 now = SDL_GetTicks();
436
437 switch (msgType)
438 {
439 case MSG_PING:
440 case MSG_PONG:
441 case MSG_LOBBY:
442 case MSG_GAME_INFO:
443 {
444 std::map<IPaddress, Connection>::iterator it = connections.find(address);
445 if (it == connections.end())
446 {
447 return;
448 }
449 Connection& connection = it->second;
450
451 if (timestamp <= connection.lastTimestamp)
452 {
453 return;
454 }
455 connection.lastTimestamp = timestamp;
456
457 connection.lastRecive = now;
458
459 switch (msgType)
460 {
461 case MSG_PING:
462 {
463 msg.reset();
464 msg.write8(MSG_PONG);
465 msg.write32(now);
466 send(address);
467 connection.lastSend = SDL_GetTicks();
468 break;
469 }
470 case MSG_LOBBY:
471 {
472 if (connectionType == NET_LOBBY)
473 {
474 if (connection.gameInfo)
475 {
476 delete connection.gameInfo;
477 connection.gameInfo = 0;
478 gameList.update(address, 0);
479 }
480 Uint32 lastChatMessageDelivered = msg.read32();
481 if (lastChatMessageDelivered > connection.lastChatMessageDelivered)
482 {
483 connection.lastChatMessageDelivered = lastChatMessageDelivered;
484 }
485 Uint32 chatMessage = msg.read32();
486 if (chatMessage != 0 && chatMessage > connection.lastChatMessageRecived)
487 {
488 connection.lastChatMessageRecived = chatMessage;
489 chat.addMessage(msg.readString(), CHAT_COLOR2);
490 }
491
492 if (chatMessage != 0)
493 {
494 // It's necessary to send this message here
495 // to make sure the sender knows that we
496 // have received the chat message.
497 sendLobbyMessage(connection, address);
498 }
499 }
500 else if (connectionType == NET_GAME_OWNER)
501 {
502 if (blacklist.count(address.host))
503 {
504 return;
505 }
506 msg.reset();
507 msg.write8(MSG_GAME_INFO);
508 msg.write32(SDL_GetTicks());
509 msg.write32(timestamp);
510 msg.writeString(game.name);
511 msg.write8(reservedPlayers);
512 msg.write8(game.maxPlayers);
513 msg.write8(game.tournament);
514 msg.write8(game.collisions);
515 send(address);
516 connection.lastSend = SDL_GetTicks();
517 }
518 break;
519 }
520 case MSG_GAME_INFO:
521 {
522 if (!connection.gameInfo)
523 {
524 connection.gameInfo = new NetworkGameInfo();
525 }
526 connection.gameInfo->ping = now - msg.read32();
527 connection.gameInfo->name = msg.readString();
528 connection.gameInfo->players = msg.read8();
529 connection.gameInfo->maxPlayers = msg.read8();
530 connection.gameInfo->tournament = msg.read8();
531 connection.gameInfo->collisions = msg.read8();
532
533 gameList.update(address, connection.gameInfo);
534 }
535 }
536 break;
537 }
538 case MSG_JOIN_START:
539 {
540 if (blacklist.count(address.host))
541 {
542 return;
543 }
544 int maxPlayers = msg.read8();
545 if (maxPlayers < 1 || maxPlayers > 8)
546 {
547 return;
548 }
549 std::map<IPaddress, JoinInProgress>::iterator it = joinInProgress.find(address);
550 if (it != joinInProgress.end())
551 {
552 // Throw away the old join progress.
553 JoinInProgress& jip = it->second;
554 if (timestamp <= jip.lastTimestamp)
555 {
556 return;
557 }
558 reservedCars &= ~jip.reservedCars;
559 reservedPlayers -= jip.reservedPlayers;
560 joinInProgress.erase(it);
561 }
562
563 if (reservedPlayers < game.maxPlayers)
564 {
565 JoinInProgress& jip = joinInProgress[address];
566 jip.timeout = now + JOIN_TIMEOUT;
567 jip.reservedPlayers = 1;
568 ++reservedPlayers;
569 jip.reservedCars = 0;
570 jip.lastTimestamp = timestamp;
571 jip.maxPlayers = maxPlayers;
572 jip.noMore = false;
573
574 sendJoinStatus(address, JOIN_MORE_CARS, 0, reservedCars);
575 }
576 else
577 {
578 sendJoinStatus(address, JOIN_ERROR, 0, reservedCars);
579 }
580 break;
581 }
582 case MSG_JOIN_CAR:
583 {
584 std::map<IPaddress, JoinInProgress>::iterator it = joinInProgress.find(address);
585 if (it == joinInProgress.end())
586 {
587 return;
588 }
589 JoinInProgress& jip = it->second;
590 if (timestamp <= jip.lastTimestamp)
591 {
592 return;
593 }
594 jip.lastTimestamp = timestamp;
595 Uint8 car = msg.read8();
596 if (car >= 8)
597 {
598 return;
599 }
600 jip.timeout = now + JOIN_TIMEOUT;
601 Uint8 carBit = 1 << car;
602
603 if (jip.noMore)
604 {
605 sendJoinStatus(address, JOIN_NO_MORE_CARS, jip.cars.size(), reservedCars);
606 }
607 else if ((reservedCars & carBit) != 0)
608 {
609 // this car has already been taken
610 sendJoinStatus(address, JOIN_MORE_CARS, jip.cars.size(), reservedCars);
611 }
612 else
613 {
614 jip.cars.push_back(car);
615 jip.reservedCars |= carBit;
616 reservedCars |= carBit;
617
618 if (jip.reservedPlayers < game.maxPlayersPerClient &&
619 reservedPlayers < game.maxPlayers &&
620 jip.reservedPlayers < jip.maxPlayers)
621 {
622 ++reservedPlayers;
623 ++jip.reservedPlayers;
624
625 sendJoinStatus(address, JOIN_MORE_CARS, jip.cars.size(), reservedCars);
626 }
627 else
628 {
629 jip.noMore = true;
630 sendJoinStatus(address, JOIN_NO_MORE_CARS, jip.cars.size(), reservedCars);
631 }
632 }
633 break;
634 }
635 case MSG_JOIN_END:
636 {
637 std::map<IPaddress, JoinInProgress>::iterator it = joinInProgress.find(address);
638 if (it == joinInProgress.end())
639 {
640 // Check if player has already joined.
641 std::map<IPaddress, GamePlayer>::iterator it = gameClients.find(address);
642 if (it != gameClients.end())
643 {
644 GamePlayer& gp = it->second;
645 sendJoinStatus(address, JOIN_HAS_ENDED, gp.cars.size(), reservedCars);
646 }
647 return;
648 }
649 JoinInProgress& jip = it->second;
650 if (timestamp <= jip.lastTimestamp)
651 {
652 return;
653 }
654
655 GamePlayer& p = gameClients[address];
656 for (std::size_t i = 0; i < jip.cars.size(); ++i)
657 {
658 NetworkRaceCar nrc;
659 nrc.player = &p;
660 nrc.car = jip.cars[i];
661 nrc.name = uniqueName(msg.readString());
662 nrc.id = -1;
663 nrc.time = 0;
664 nrc.points = 0;
665 nrc.driver = i;
666 nrc.human = true;
667 p.cars.push_back(nrc);
668 sendChatMessage(nrc.name + " has joined!", nrc.car);
669 }
670
671 // The client has joined successfully!
672 sendJoinStatus(address, JOIN_HAS_ENDED, jip.cars.size(), reservedCars);
673
674 p.gameStateId = NETWORK_GAME_STATE_BLANK;
675 p.lastTick = 0;
676 p.lastChatMessageDelivered = lastChatMessage;
677 p.lastRecive = now;
678
679 joinInProgress.erase(address);
680 break;
681 }
682 case MSG_JOIN_QUIT:
683 {
684 std::map<IPaddress, JoinInProgress>::iterator it = joinInProgress.find(address);
685 if (it == joinInProgress.end())
686 {
687 return;
688 }
689 JoinInProgress& jip = it->second;
690 if (timestamp <= jip.lastTimestamp)
691 {
692 return;
693 }
694 reservedCars &= ~jip.reservedCars;
695 reservedPlayers -= jip.reservedPlayers;
696 joinInProgress.erase(it);
697 break;
698 }
699 case MSG_JOIN_STATUS:
700 {
701 if (connectionType == NET_LOBBY)
702 {
703 if (joinStatus.address == address)
704 {
705 if (timestamp <= joinStatus.lastTimestamp)
706 {
707 return;
708 }
709 joinStatus.updated = true;
710 joinStatus.lastTimestamp = timestamp;
711 joinStatus.state = msg.read8();
712 joinStatus.joinedPlayers = msg.read8();
713 joinStatus.reservedCars = msg.read8();
714 if (joinStatus.state > JOIN_ERROR ||
715 joinStatus.joinedPlayers > 7)
716 {
717 joinStatus.state = JOIN_ERROR;
718 }
719 if (joinStatus.state == JOIN_HAS_ENDED)
720 {
721 int n = msg.read8();
722 chatInput.clear();
723 if (n > 8 || n < 0)
724 {
725 chatInput.addPlayer("error");
726 }
727 else
728 {
729 for (int i = 0; i < n; ++i)
730 {
731 std::string name = msg.readString();
732 int car = msg.read8();
733 chatInput.addPlayer(name, car);
734 }
735 }
736 }
737 }
738 }
739 break;
740 }
741 case MSG_NEW_STATE_RACE:
742 case MSG_NEW_STATE_TIMES:
743 case MSG_NEW_STATE_POINTS:
744 case MSG_RACE_STATE:
745 case MSG_END_GAME:
746 case MSG_GAME_CHAT_INFO:
747 {
748 if (connectionType != NET_GAME_PLAYER)
749 {
750 return;
751 }
752 if (address != gameOwner)
753 {
754 return;
755 }
756 if (timestamp <= lastGameTimestamp)
757 {
758 return;
759 }
760 lastGameTimestamp = timestamp;
761 lastGameRecive = now;
762 if (msgType == MSG_NEW_STATE_RACE ||
763 msgType == MSG_NEW_STATE_TIMES ||
764 msgType == MSG_NEW_STATE_POINTS)
765 {
766 Uint32 newGameStateCount = msg.read32();
767 if (newGameStateCount <= gameStateCount)
768 {
769 if (newGameStateCount == gameStateCount)
770 {
771 // Resend game state info in case the game
772 // owner has not received that information.
773 msg.reset();
774 msg.write8(MSG_STATE_STATUS);
775 msg.write32(SDL_GetTicks());
776 msg.write8(gameStateId);
777 msg.write32(gameStateCount);
778 send(address);
779 lastGameSent = SDL_GetTicks();
780 }
781 return;
782 }
783
784 switch (msgType)
785 {
786 case MSG_NEW_STATE_RACE:
787 {
788 Uint8 laps = msg.read8();
789 if (laps > 9)
790 {
791 return;
792 }
793 bool collisions = msg.read8() != 0;
794
795 map.read(msg);
796 if (!map.isValid())
797 {
798 return;
799 }
800
801 std::size_t carCount = msg.read8();
802 if (carCount < 1 || carCount > 8)
803 {
804 return;
805 }
806 std::vector<int> cars(carCount);
807 std::vector<Driver*> drivers(carCount);
808 localCars.clear();
809 inputMask = 0;
810 for (std::size_t i = 0; i < carCount; ++i)
811 {
812 Uint8 car = msg.read8();
813 if (car >= 8)
814 {
815 return;
816 }
817 cars[i] = car;
818
819 Uint8 driver = msg.read8();
820 if (driver < 8)
821 {
822 drivers[i] = StateManager::getInstance().getDriver(driver);
823
824 NetworkRaceCar nrc;
825 nrc.player = 0;
826 nrc.car = car;
827 nrc.id = i;
828 nrc.driver = driver;
829 nrc.time = 0;
830 nrc.points = 0;
831 nrc.human = true;
832 localCars.push_back(nrc);
833 inputMask |= 0xF << (i * 4);
834 }
835 }
836
837 // Start race!
838 std::vector<std::string> names(drivers.size());
839 RaceState* raceState = new RaceState(map, RaceSetup(drivers, cars, names, laps, 1, false, collisions), this);
840 setNewGameState(raceState);
841 track = raceState->getTrack();
842 for (std::size_t i = 0; i < TRACK_BUFFER_SIZE; ++i)
843 {
844 trackStateBuffer[i].setCars(carCount);
845 track->save(trackStateBuffer[i]);
846 }
847 for (std::size_t i = 0; i < INPUT_BUFFER_SIZE; ++i)
848 {
849 inputBuffer[i] = 0;
850 }
851
852 gameStateId = NETWORK_GAME_STATE_RACE;
853
854 raceTick = 0;
855 newTrackInfoReady = false;
856 newTrackInfoCounter = 0;
857 newTrackStateTick = 0;
858
859 break;
860 }
861 case MSG_NEW_STATE_TIMES:
862 case MSG_NEW_STATE_POINTS:
863 {
864 Uint8 tracks = msg.read8();
865 Uint8 currentTrack = msg.read8();
866
867 Uint8 n = msg.read8();
868 if (n > 8)
869 {
870 return;
871 }
872 std::vector<Driver*> drivers(n);
873 std::vector<int> cars(n);
874 std::vector<std::string> names(n);
875 std::vector<int> values(n);
876 for (int i = 0; i < n; ++i)
877 {
878 cars[i] = msg.read8() % 8;
879 names[i] = msg.readString();
880 values[i] = msg.read32();
881 }
882 RaceSetup raceSetup(drivers,cars ,names, 0, tracks, tracks > 1, 0);
883 raceSetup.setTrack(currentTrack);
884
885 void (RaceSetup::*setValue)(int, int);
886 if (msgType == MSG_NEW_STATE_TIMES)
887 {
888 gameStateId = NETWORK_GAME_STATE_TIMES;
889 setValue = &RaceSetup::setPlayerTime;
890 }
891 else
892 {
893 gameStateId = NETWORK_GAME_STATE_POINTS;
894 setValue = &RaceSetup::setPlayerPoints;
895 }
896 for (int i = 0; i < n; ++i)
897 {
898 (raceSetup.*setValue)(i, values[i]);
899 }
900
901 setNewGameState(new ResultState(raceSetup, this, gameStateId == NETWORK_GAME_STATE_POINTS));
902 break;
903 }
904 }
905
906 gameStateCount = newGameStateCount;
907
908 msg.reset();
909 msg.write8(MSG_STATE_STATUS);
910 msg.write32(SDL_GetTicks());
911 msg.write8(gameStateId);
912 msg.write32(gameStateCount);
913 send(address);
914 lastGameSent = SDL_GetTicks();
915 }
916 else if (msgType == MSG_RACE_STATE)
917 {
918 if (gameStateId != NETWORK_GAME_STATE_RACE)
919 {
920 return;
921 }
922
923 Uint8 carCount = msg.read8();
924 Uint8 removedCarCount = msg.read8();
925 Uint8 removedCar;
926 for (int i = 0; i < removedCarCount; ++i)
927 {
928 removedCar = msg.read8();
929 if (carCount < track->getCarCount())
930 {
931 eraseCar(removedCar);
932 }
933 }
934
935 Uint32 tick = msg.read32();
936 Uint32 stateTick = msg.read32();
937 if (stateTick > tick)
938 {
939 return;
940 }
941
942 // Last message received by game owner.
943 Uint32 ticksTooFast = msg.read32();
944 Uint32 myGameOwnerTimestamp = msg.read32();
945
946 if (ticksTooFast > 0 && myGameOwnerTimestamp > lastSlowDown)
947 {
948 // We are running too fast!
949 raceTick -= ticksTooFast;
950 lastSlowDown = now;
951 }
952
953 // It's important that we don't use else-if here because
954 // the above if statement can make raceTick greater than
955 // tick if ticksTooFast is faulty. It is also possible
956 // that we are running too slow even though the game
957 // owner noticed we ran too fast only recently.
958
959 if (tick > raceTick)
960 {
961 // We are running too slow!
962 raceTick = tick;
963 }
964
965 if (raceTick - stateTick > INPUT_BUFFER_SIZE)
966 {
967 // We can't handle this in a good way so it's better
968 // to do nothing and hope the sync improves.
969 return;
970 }
971
972 // We use one of the track states in the
973 // buffer to avoid unnecessary reallocations.
974 TrackState& trackState = trackStateBuffer[0];
975 trackState.read(msg, track->getCarCount());
976
977 track->restore(trackState);
978
979 // This input might not look useful but it will be used in the
980 // second loop below if stateTick == tick && tick < raceTick.
981 Uint32 input = msg.read32();
982
983 for (Uint32 t = stateTick + 1; t <= tick; ++t)
984 {
985 Uint32 i = raceTick - t;
986 input = msg.read32();
987 inputBuffer[i] = (inputBuffer[i] & inputMask) | (input & ~inputMask);
988 }
989
990 for (Uint32 t = tick + 1; t <= raceTick; ++t)
991 {
992 Uint32 i = raceTick - t;
993 inputBuffer[i] = (inputBuffer[i] & inputMask) | (input & ~inputMask);
994 }
995
996 for (Uint32 t = stateTick + 1; t <= raceTick; ++t)
997 {
998 Uint32 i = raceTick - t;
999 track->update(TRACK_TIME_STEP * 0.001, &inputBuffer[i]);
1000 }
1001
1002 readChatMessage();
1003 }
1004 else if (msgType == MSG_END_GAME)
1005 {
1006 setNewGameState(new ErrorState("End of game", "The network game has ended", new NetworkMenu(this)));
1007 }
1008 else if (msgType == MSG_GAME_CHAT_INFO)
1009 {
1010 if (readChatMessage())
1011 {
1012 // Force message to be sent as soon as possible to
1013 // inform the game owner that we have received the
1014 // message.
1015 lastGameSent = 0;
1016 }
1017 }
1018 break;
1019 }
1020 case MSG_STATE_STATUS:
1021 case MSG_RACE_INPUT:
1022 case MSG_QUIT_GAME:
1023 case MSG_GAME_CHAT_ADD:
1024 {
1025 if (connectionType != NET_GAME_OWNER)
1026 {
1027 return;
1028 }
1029 std::map<IPaddress, GamePlayer>::iterator it = gameClients.find(address);
1030 if (it == gameClients.end())
1031 {
1032 break;
1033 }
1034 GamePlayer& gp = it->second;
1035 if (timestamp <= gp.lastTimestamp)
1036 {
1037 return;
1038 }
1039 gp.lastTimestamp = timestamp;
1040 gp.lastRecive = now;
1041 if (msgType == MSG_STATE_STATUS)
1042 {
1043 int newPlayerGameStateId = msg.read8();
1044 Uint32 playerStateCount = msg.read32();
1045 if (gp.gameStateId != newPlayerGameStateId && playerStateCount == gameStateCount)
1046 {
1047 gp.gameStateId = newPlayerGameStateId;
1048 }
1049 }
1050 else if (msgType == MSG_RACE_INPUT)
1051 {
1052 if (gameStateId != NETWORK_GAME_STATE_RACE)
1053 {
1054 return;
1055 }
1056
1057 readChatMessage(gp);
1058
1059 Uint32 tick = msg.read32();
1060 gp.ticksTooFast = tick > raceTick ? tick - raceTick : 0;
1061
1062 if (gp.ticksTooFast > 0)
1063 {
1064 // No point handling out of sync input.
1065 // Better wait until we are in sync.
1066 return;
1067 }
1068
1069 if (tick < gp.lastTick)
1070 {
1071 // This could happen when the player adjusts for out
1072 // of sync so we just modify the last tick value so
1073 // that it will work in the calculations that follow
1074 gp.lastTick = tick;
1075 }
1076
1077 Uint32 stepBackNeeded = raceTick - gp.lastTick;
1078 Uint32 stepBackPossible = (TRACK_BUFFER_SIZE - 1) * NETWORK_STEP + raceTick % NETWORK_STEP;
1079
1080 Uint32 stepBack = std::min(stepBackNeeded, stepBackPossible);
1081 Uint32 restoreTick = raceTick - stepBack;
1082 Uint32 restoreStateIndex = raceTick / NETWORK_STEP - restoreTick / NETWORK_STEP;
1083
1084 track->restore(trackStateBuffer[restoreStateIndex]);
1085
1086 // Read player input.
1087 for (Uint32 i = raceTick - tick; i < stepBack; ++i)
1088 {
1089 Uint32 preInputValue = inputBuffer[i];
1090 inputBuffer[i] = (inputBuffer[i] & ~gp.inputMask) | (msg.read32() & gp.inputMask);
1091 if (inputBuffer[i] != preInputValue)
1092 {
1093 newTrackInfoReady = true;
1094 }
1095 }
1096 for (Uint32 i = 0; i < raceTick - tick; ++i)
1097 {
1098 inputBuffer[i] = (inputBuffer[i] & ~gp.inputMask) | (inputBuffer[raceTick - tick] & gp.inputMask);
1099 }
1100 stepBack += (restoreTick % NETWORK_STEP);
1101 raceTick -= stepBack;
1102
1103 for (int i = stepBack - 1; i >= 0; --i)
1104 {
1105 track->update(TRACK_TIME_STEP * 0.001, &inputBuffer[i]);
1106 ++raceTick;
1107 if (raceTick % NETWORK_STEP == 0)
1108 {
1109 --restoreStateIndex;
1110 TrackState& trackState = trackStateBuffer[restoreStateIndex];
1111 track->save(trackState);
1112 }
1113 }
1114
1115 gp.lastTick = tick;
1116 }
1117 else if (msgType == MSG_QUIT_GAME)
1118 {
1119 erasePlayer(it);
1120 }
1121 else if (msgType == MSG_GAME_CHAT_ADD)
1122 {
1123 readChatMessage(gp);
1124 }
1125 break;
1126 }
1127 }
1128 }
1129
sendLobbyMessage(Connection & connection,const IPaddress & address)1130 void Network::sendLobbyMessage(Connection& connection, const IPaddress& address)
1131 {
1132 msg.reset();
1133 msg.write8(MSG_LOBBY);
1134 msg.write32(SDL_GetTicks());
1135 msg.write32(connection.lastChatMessageRecived);
1136 if (!chatBuffer.empty() && connection.lastChatMessageDelivered < lastChatMessage)
1137 {
1138 Uint32 messageToSend = std::max(connection.lastChatMessageDelivered, static_cast<Uint32>(lastChatMessage - chatBuffer.size())) + 1;
1139 msg.write32(messageToSend);
1140 msg.writeString(chatBuffer[lastChatMessage - messageToSend].text);
1141 }
1142 else
1143 {
1144 msg.write32(0);
1145 }
1146 send(address);
1147 connection.lastSend = SDL_GetTicks();
1148 }
1149
onConnectionTimeout(const IPaddress & addr)1150 void Network::onConnectionTimeout(const IPaddress& addr)
1151 {
1152 }
1153
send(IPaddress address)1154 void Network::send(IPaddress address)
1155 {
1156 UDPpacket& packet = msg.getPacket();
1157 packet.address = address;
1158 SDLNet_UDP_Send(socket, -1, &packet);
1159 }
1160
receive()1161 bool Network::receive()
1162 {
1163 msg.reset();
1164 UDPpacket& packet = msg.getPacket();
1165 return SDLNet_UDP_Recv(socket, &packet) == 1;
1166 }
1167
setGameState(GameState * newGameState,bool chatOn,bool gameListOn)1168 void Network::setGameState(GameState* newGameState, bool chatOn, bool gameListOn)
1169 {
1170 this->chatOn = chatOn;
1171 gameState = newGameState;
1172 if (gameState)
1173 {
1174 gameState->addRenderObject(statusRenderObject);
1175 }
1176
1177 chat.setGameState(chatOn ? gameState : 0);
1178 chatInput.setGameState(chatOn && chat.isEnabled() ? gameState : 0);
1179 gameList.setGameState(gameListOn ? gameState : 0);
1180 }
1181
enableChatInput(bool chatInputOn)1182 void Network::enableChatInput(bool chatInputOn)
1183 {
1184 chatInput.setGameState(chatInputOn && chat.isEnabled() ? gameState : 0);
1185 }
1186
onEvent(const SDL_Event & event,bool isDriving)1187 bool Network::onEvent(const SDL_Event& event, bool isDriving)
1188 {
1189 if (event.type == SDL_KEYDOWN)
1190 {
1191 SDLKey key = event.key.keysym.sym;
1192
1193 if (key == SDLK_F5 && connectionType == NET_LOBBY)
1194 {
1195 refreshAsNeeded();
1196 }
1197 else if (!chatOn)
1198 {
1199 return false;
1200 }
1201 else if (key == SDLK_TAB)
1202 {
1203 chat.toggle();
1204 chatInput.setGameState(chat.isEnabled() ? gameState : 0);
1205 return true;
1206 }
1207 else if (chat.isEnabled())
1208 {
1209 // Don't start inputting a new chat message if the key is used for driving.
1210 if (isDriving && !chatInput.isVisible())
1211 {
1212 assert(gameStateId == NETWORK_GAME_STATE_RACE);
1213
1214 for (std::size_t i = 0; i < localCars.size(); ++i)
1215 {
1216 const NetworkRaceCar& car = localCars[i];
1217
1218 if (car.id >= 0 && car.human && StateManager::getInstance().getDriver(car.driver)->isUsingKey(key))
1219 {
1220 // Wait a small time period after the car has finished to avoid accidental chat input.
1221 const double CHAT_KEY_DELAY = 1.0; // seconds
1222 if (!track->isCarFinished(car.id) || track->getCarFinishTime(car.id) + CHAT_KEY_DELAY > track->getRaceTime())
1223 {
1224 // The key is used for driving!
1225 return false;
1226 }
1227 }
1228 }
1229 }
1230
1231 if (chatInput.onEvent(event))
1232 {
1233 if (chatInput.isReady())
1234 {
1235 std::string text = chatInput.fetch();
1236 std::istringstream iss(text);
1237 iss.ignore(1000, ':'); // ignore username
1238 iss.ignore(); // ignore space
1239 if (iss.get() == '/')
1240 {
1241 if (connectionType == NET_LOBBY)
1242 {
1243 chat.addMessage("No commands allowed here!");
1244 }
1245 else if (connectionType == NET_GAME_PLAYER)
1246 {
1247 chat.addMessage("Commands can only be used by the \"game owner\"!");
1248 }
1249 else
1250 {
1251 std::string command;
1252 if (iss >> command)
1253 {
1254 if (command == "help")
1255 {
1256 chat.addMessage("Commands: /ban /kick /kickall /mute /list /color");
1257 }
1258 else if (command == "list")
1259 {
1260 std::vector<std::string> names;
1261
1262 std::vector<NetworkRaceCar>::iterator itCar;
1263 for (itCar = localCars.begin(); itCar != localCars.end(); ++itCar)
1264 {
1265 names.push_back(itCar->name);
1266 }
1267
1268 std::map<IPaddress, GamePlayer>::iterator itPlayer;
1269 for (itPlayer = gameClients.begin(); itPlayer != gameClients.end(); ++itPlayer)
1270 {
1271 GamePlayer& gp = itPlayer->second;
1272 for (itCar = gp.cars.begin(); itCar != gp.cars.end(); ++itCar)
1273 {
1274 names.push_back(itCar->name);
1275 }
1276 }
1277
1278 std::sort(names.begin(), names.end());
1279
1280 std::string message;
1281 for (std::size_t i = 0; i < names.size(); ++i)
1282 {
1283 message += (message.empty() ? "" : ", ") + names[i];
1284 }
1285 chat.addMessage(message);
1286 }
1287 else if (command == "color" ||
1288 command == "colour" ||
1289 command == "ban" ||
1290 command == "kick" ||
1291 command == "kickall" ||
1292 command == "mute")
1293 {
1294 std::map<IPaddress, GamePlayer>::iterator itPlayer = gameClients.end();
1295 std::vector<NetworkRaceCar>::iterator itCar;
1296 bool carFound = false;
1297 std::string username;
1298 iss >> username;
1299 std::string token;
1300 while (iss >> token)
1301 {
1302 username += " " + token;
1303 }
1304 for (itCar = localCars.begin(); itCar != localCars.end(); ++itCar)
1305 {
1306 if (itCar->name == username)
1307 {
1308 carFound = true;
1309 break;
1310 }
1311 }
1312 if (!carFound)
1313 {
1314 for (itPlayer = gameClients.begin(); itPlayer != gameClients.end(); ++itPlayer)
1315 {
1316 GamePlayer& gp = itPlayer->second;
1317 for (itCar = gp.cars.begin(); itCar != gp.cars.end(); ++itCar)
1318 {
1319 if (itCar->name == username)
1320 {
1321 carFound = true;
1322 break;
1323 }
1324 }
1325 if (carFound)
1326 {
1327 break;
1328 }
1329 }
1330 }
1331 if (!carFound)
1332 {
1333 if (username.empty())
1334 {
1335 chat.addMessage("Missing username!");
1336 }
1337 else
1338 {
1339 chat.addMessage("No user named " + username +"!");
1340 }
1341 }
1342 else if (command == "color" ||
1343 command == "colour")
1344 {
1345 chat.addMessage(username + " drives a " + carColorName(itCar->car) + " car", carColor(itCar->car));
1346 }
1347 else if (command == "ban")
1348 {
1349 if (itPlayer != gameClients.end())
1350 {
1351 GamePlayer& gp = itPlayer->second;
1352 itCar = gp.cars.begin();
1353 for (itCar = gp.cars.begin(); itCar != gp.cars.end();)
1354 {
1355 itCar = eraseCar(itCar, "banned");
1356 }
1357 blacklist.insert(itPlayer->first.host);
1358 }
1359 else
1360 {
1361 chat.addMessage("You can't ban yourself!");
1362 }
1363 }
1364 else if (command == "kick")
1365 {
1366 if (itPlayer != gameClients.end())
1367 {
1368 eraseCar(itCar, "kicked");
1369 }
1370 else
1371 {
1372 std::size_t localHumanPlayers = 0;
1373 for (std::size_t i = 0; i < localCars.size(); ++i)
1374 {
1375 if (localCars[i].human)
1376 {
1377 ++localHumanPlayers;
1378 }
1379 }
1380
1381 if (!itCar->human || localHumanPlayers > 1)
1382 {
1383 eraseCar(itCar, "kicked");
1384 }
1385 else
1386 {
1387 chat.addMessage("You need at least one player!");
1388 }
1389 }
1390 }
1391 else if (command == "kickall")
1392 {
1393 if (itPlayer != gameClients.end())
1394 {
1395 GamePlayer& gp = itPlayer->second;
1396 itCar = gp.cars.begin();
1397 for (itCar = gp.cars.begin(); itCar != gp.cars.end();)
1398 {
1399 itCar = eraseCar(itCar, "kicked");
1400 }
1401 }
1402 else
1403 {
1404 chat.addMessage("You need at least one player!");
1405 }
1406 }
1407 else if (command == "mute")
1408 {
1409 if (itPlayer != gameClients.end())
1410 {
1411 GamePlayer& gp = itPlayer->second;
1412 gp.mute = !gp.mute;
1413 sendChatMessage(username + " has been " + (gp.mute ? "" : "un") + "muted!", itCar->car);
1414 }
1415 else
1416 {
1417 chat.addMessage("You can't mute yourself!");
1418 }
1419 }
1420 }
1421 else
1422 {
1423 chat.addMessage("Invalid command! Try /help");
1424 }
1425
1426 }
1427 }
1428 }
1429 else
1430 {
1431 sendChatMessage(text, chatInput.fetchCar());
1432 }
1433 }
1434 return true;
1435 }
1436 }
1437 }
1438 return false;
1439 }
1440
setGame(const std::string & name,int maxPlayers,int maxPlayersPerClient,int laps,int tracks,int collisions)1441 void Network::setGame(const std::string& name, int maxPlayers, int maxPlayersPerClient, int laps, int tracks, int collisions)
1442 {
1443 game.name = name;
1444 game.maxPlayers = maxPlayers;
1445 game.maxPlayersPerClient = maxPlayersPerClient;
1446 game.laps = laps;
1447 game.tracks = tracks;
1448 game.tournament = tracks > 1;
1449 game.collisions = collisions;
1450 }
createGame(Uint8 reservedCars,std::vector<int> cars)1451 void Network::createGame(Uint8 reservedCars, std::vector<int> cars)
1452 {
1453 chat.clear();
1454 chatInput.clear();
1455 chatBuffer.clear();
1456 removedCars.clear();
1457 gameClients.clear();
1458 joinInProgress.clear();
1459 gameClients.clear();
1460 localCars.clear();
1461
1462 connectionType = NET_GAME_OWNER;
1463 gameStateId = NETWORK_GAME_STATE_RACE; // Start race right away.
1464
1465 std::vector<int> freeCars(8);
1466 for (int i = 0; i < 8; ++i)
1467 {
1468 freeCars[i] = i;
1469 }
1470
1471 for (std::size_t i = 0; i < cars.size(); ++i)
1472 {
1473 NetworkRaceCar nrc;
1474 nrc.player = 0;
1475 nrc.name = Settings::players.humanNames[i];
1476 nrc.car = cars[i];
1477 nrc.id = -1;
1478 nrc.driver = i;
1479 nrc.time = 0;
1480 nrc.points = 0;
1481 nrc.human = true;
1482 localCars.push_back(nrc);
1483 freeCars.erase(std::remove(freeCars.begin(), freeCars.end(), nrc.car), freeCars.end());
1484 chatInput.addPlayer(nrc.name, nrc.car);
1485 }
1486
1487 std::random_shuffle(freeCars.begin(), freeCars.end());
1488
1489 // Add computer players
1490 for (int i = 0; i < Settings::network.computerPlayers && i < int(freeCars.size()); ++i)
1491 {
1492 NetworkRaceCar nrc;
1493 nrc.player = 0;
1494 nrc.name = Settings::players.computerNames[i];
1495 nrc.car = freeCars[i];
1496 nrc.id = -1;
1497 nrc.driver = i;
1498 nrc.time = 0;
1499 nrc.points = 0;
1500 nrc.human = false;
1501 localCars.push_back(nrc);
1502 cars.push_back(nrc.car);
1503 reservedCars |= 1 << nrc.car;
1504 }
1505
1506 reservedPlayers = cars.size();
1507 this->reservedCars = reservedCars;
1508
1509 gameStateCount = 0;
1510 startRace();
1511 }
1512
getGameList()1513 GameList& Network::getGameList()
1514 {
1515 return gameList;
1516 }
1517
sendJoinStart()1518 void Network::sendJoinStart()
1519 {
1520 msg.reset();
1521 msg.write8(MSG_JOIN_START);
1522 msg.write32(SDL_GetTicks());
1523 msg.write8(Settings::network.players);
1524 send(joinStatus.address);
1525 }
1526
sendJoinCar(int car)1527 void Network::sendJoinCar(int car)
1528 {
1529 msg.reset();
1530 msg.write8(MSG_JOIN_CAR);
1531 msg.write32(SDL_GetTicks());
1532 msg.write8(car);
1533 send(joinStatus.address);
1534 }
1535
sendJoinEnd()1536 void Network::sendJoinEnd()
1537 {
1538 msg.reset();
1539 msg.write8(MSG_JOIN_END);
1540 msg.write32(SDL_GetTicks());
1541 for (int i = 0; i < 8; ++i)
1542 {
1543 msg.writeString(Settings::players.humanNames[i]);
1544 }
1545 send(joinStatus.address);
1546 }
1547
join(const IPaddress & address)1548 void Network::join(const IPaddress& address)
1549 {
1550 joinStatus.updated = false;
1551 joinStatus.address = address;
1552 joinStatus.state = JOIN_NOT_STARTED;
1553 joinStatus.joinedPlayers = 0;
1554 joinStatus.reservedCars = 0;
1555 joinStatus.lastTimestamp = 0;
1556 }
1557
sendJoinStatus(const IPaddress & address,int state,Uint8 joinedPlayers,Uint8 reservedCars)1558 void Network::sendJoinStatus(const IPaddress& address, int state, Uint8 joinedPlayers, Uint8 reservedCars)
1559 {
1560 msg.reset();
1561 msg.write8(MSG_JOIN_STATUS);
1562 msg.write32(SDL_GetTicks());
1563 msg.write8(state);
1564 msg.write8(joinedPlayers);
1565 msg.write8(reservedCars);
1566 if (state == JOIN_HAS_ENDED)
1567 {
1568 GamePlayer& gp = gameClients[address];
1569 msg.write8(gp.cars.size());
1570 for (std::size_t i = 0; i < gp.cars.size(); ++i)
1571 {
1572 msg.writeString(gp.cars[i].name);
1573 msg.write8(gp.cars[i].car);
1574 }
1575 }
1576 send(address);
1577 }
1578
getJoinStatus(JoinStatus & status)1579 bool Network::getJoinStatus(JoinStatus& status)
1580 {
1581 status = joinStatus;
1582 joinStatus.updated = false;
1583 return status.updated;
1584 }
1585
getNewGameState()1586 GameState* Network::getNewGameState()
1587 {
1588 GameState* gs = newGameState;
1589 newGameState = 0;
1590 return gs;
1591 }
setNewGameState(GameState * gs)1592 void Network::setNewGameState(GameState* gs)
1593 {
1594 delete newGameState;
1595 newGameState = gs;
1596 }
1597
join()1598 void Network::join()
1599 {
1600 connectionType = NET_GAME_PLAYER;
1601 gameOwner = joinStatus.address;
1602 gameStateId = NETWORK_GAME_STATE_BLANK;
1603 gameStateCount = 0;
1604 lastGameRecive = SDL_GetTicks();
1605
1606 // Instead calling connections.clear() here we simply let them
1607 // time out to make sure all the necessary cleanup is made.
1608
1609 chat.clear();
1610 // chatInput is cleared elsewhere.
1611 chatBuffer.clear();
1612
1613 setNewGameState(new NetworkBlankState(this));
1614 }
1615
raceCarSorter(const NetworkRaceCar * c1,const NetworkRaceCar * c2)1616 bool raceCarSorter(const NetworkRaceCar* c1, const NetworkRaceCar* c2)
1617 {
1618 int t1 = c1->time > 0 ? c1->time : std::numeric_limits<int>::max();
1619 int t2 = c2->time > 0 ? c2->time : std::numeric_limits<int>::max();
1620 return t1 > t2;
1621 }
1622
startRace()1623 void Network::startRace()
1624 {
1625 // Add all cars.
1626 raceCars.clear();
1627 for (std::size_t i = 0; i < localCars.size(); ++i)
1628 {
1629 raceCars.push_back(&localCars[i]);
1630 }
1631 std::map<IPaddress, GamePlayer>::iterator it;
1632 for (it = gameClients.begin(); it != gameClients.end(); ++it)
1633 {
1634 GamePlayer& gp = it->second;
1635 std::vector<NetworkRaceCar>& nrc = gp.cars;
1636 for (std::size_t i = 0; i < nrc.size(); ++i)
1637 {
1638 raceCars.push_back(&nrc[i]);
1639 }
1640 gp.inputMask = 0;
1641 gp.lastTick = 0;
1642 }
1643
1644 // Sort by time of previous race.
1645 std::sort(raceCars.begin(), raceCars.end(), raceCarSorter);
1646
1647 // Update and collect information.
1648 std::vector<Driver*> drivers(raceCars.size());
1649 std::vector<int> cars(raceCars.size());
1650 std::vector<std::string> names(raceCars.size());
1651 for (std::size_t i = 0; i < raceCars.size(); ++i)
1652 {
1653 NetworkRaceCar& car = *raceCars[i];
1654 car.id = i;
1655 cars[i] = car.car;
1656 names[i] = car.name;
1657 if (car.player)
1658 {
1659 car.player->inputMask |= 0xF << (i * 4);
1660 }
1661 else
1662 {
1663 assert(car.driver < 8);
1664 if (car.human)
1665 {
1666 drivers[i] = StateManager::getInstance().getDriver(car.driver);
1667 }
1668 else
1669 {
1670 int difficulty = Settings::players.computerDifficulties[car.driver];
1671 if (difficulty < 0)
1672 {
1673 difficulty = Settings::network.computerDifficulty;
1674 }
1675 drivers[i] = &AIDriver::getInstance(difficulty);
1676 }
1677 }
1678 }
1679
1680 map = Map::generate();
1681
1682 // Start new race!
1683 ++gameStateCount;
1684 gameStateId = NETWORK_GAME_STATE_RACE;
1685
1686 RaceSetup raceSetup(drivers, cars, names, Settings::network.laps, Settings::network.tracks, Settings::network.tournament, Settings::network.collisions);
1687 raceSetup.setTrack(game.track);
1688
1689 for (std::size_t i = 0; i < raceCars.size(); ++i)
1690 {
1691 raceSetup.setPlayerPoints(raceCars[i]->id, raceCars[i]->points);
1692 }
1693
1694 RaceState* raceState = new RaceState(map, raceSetup, this);
1695 setNewGameState(raceState);
1696 track = raceState->getTrack();
1697 for (std::size_t i = 0; i < TRACK_BUFFER_SIZE; ++i)
1698 {
1699 trackStateBuffer[i].setCars(raceCars.size());
1700 track->save(trackStateBuffer[i]);
1701 }
1702 for (std::size_t i = 0; i < INPUT_BUFFER_SIZE; ++i)
1703 {
1704 inputBuffer[i] = 0;
1705 }
1706
1707 raceTick = 0;
1708 newTrackInfoReady = true; // Send state as soon as possible!
1709 newTrackInfoCounter = 0;
1710 newTrackStateTick = 0;
1711 }
1712
onRaceFinished(const RaceSetup & rs)1713 void Network::onRaceFinished(const RaceSetup& rs)
1714 {
1715 if (connectionType == NET_GAME_OWNER)
1716 {
1717 setNewGameState(new ResultState(rs, this));
1718 ++gameStateCount;
1719 gameStateId = NETWORK_GAME_STATE_TIMES;
1720
1721 std::vector<NetworkRaceCar*>::iterator it;
1722 for (it = raceCars.begin(); it != raceCars.end(); ++it)
1723 {
1724 NetworkRaceCar& car = **it;
1725 car.time = rs.getPlayerTime(car.id);
1726 car.points = rs.getPlayerPoints(car.id);
1727 }
1728 game.track = rs.getCurrentTrack();
1729
1730 // We call refresh here because finishing a race is not something that
1731 // can happen repeatedly without a user at the keyboard. Fetching the
1732 // list while not racing seems to be a good idea to minimize the cpu
1733 // usage while racing.
1734 refreshAsNeeded();
1735 }
1736 }
1737
onShowPoints(const RaceSetup & rs)1738 void Network::onShowPoints(const RaceSetup& rs)
1739 {
1740 if (connectionType == NET_GAME_OWNER)
1741 {
1742 setNewGameState(new ResultState(rs, this, true));
1743 ++gameStateCount;
1744 gameStateId = NETWORK_GAME_STATE_POINTS;
1745 }
1746 }
1747
isOwner() const1748 bool Network::isOwner() const
1749 {
1750 return connectionType == NET_GAME_OWNER;
1751 }
1752
sleep(Uint32 duration)1753 void Network::sleep(Uint32 duration)
1754 {
1755 // The purpose of this "sleep" function is to handle messages more
1756 // rapidly in order to get more accurate ping value.
1757 if (connectionType != NET_GAME_PLAYER && !connections.empty())
1758 {
1759 Uint32 stop = SDL_GetTicks() + duration;
1760 while (SDL_GetTicks() < stop)
1761 {
1762 if (receive())
1763 {
1764 handleMessage(msg.read8(), msg.getPacket().address);
1765 }
1766 else
1767 {
1768 SDL_Delay(1);
1769 }
1770 }
1771 }
1772 else
1773 {
1774 SDL_Delay(duration);
1775 }
1776 }
1777
sendChatMessage(const std::string & text,int car)1778 void Network::sendChatMessage(const std::string& text, int car)
1779 {
1780 SentChatMessage cm;
1781 cm.text = text;
1782 cm.timestamp = SDL_GetTicks();
1783 cm.car = car;
1784 chatBuffer.push_front(cm);
1785 ++lastChatMessage;
1786 if (connectionType != NET_GAME_PLAYER)
1787 {
1788 chat.addMessage(text, carColor(car));
1789 }
1790 }
1791
quitGame()1792 void Network::quitGame()
1793 {
1794 // For simplicity we just send the message repeatedly and hope the
1795 // other end receives it. I have no idea if routers might have some
1796 // kind of filter for identical messages that are sent rapidly so
1797 // for that reason we update the message each time so that at least
1798 // the time data is different.
1799
1800 const int QUIT_SEND_COUNT = 8;
1801 const int QUIT_SEND_DELAY = 28;
1802
1803 if (connectionType == NET_GAME_PLAYER)
1804 {
1805 for (int i = 0; i < QUIT_SEND_COUNT; ++i)
1806 {
1807 if (i > 0)
1808 {
1809 SDL_Delay(QUIT_SEND_DELAY);
1810 }
1811 msg.reset();
1812 msg.write8(MSG_QUIT_GAME);
1813 msg.write32(SDL_GetTicks());
1814 send(gameOwner);
1815 }
1816 }
1817 else if (connectionType == NET_GAME_OWNER)
1818 {
1819 for (int i = 0; i < QUIT_SEND_COUNT; ++i)
1820 {
1821 if (i > 0)
1822 {
1823 SDL_Delay(QUIT_SEND_DELAY);
1824 }
1825 msg.reset();
1826 msg.write8(MSG_END_GAME);
1827 msg.write32(SDL_GetTicks());
1828 std::map<IPaddress, GamePlayer>::iterator it;
1829 for (it = gameClients.begin(); it != gameClients.end(); ++it)
1830 {
1831 send(it->first);
1832 }
1833 }
1834 }
1835 else if (connectionType == NET_LOBBY && (joinStatus.state == JOIN_MORE_CARS || joinStatus.state == JOIN_NO_MORE_CARS))
1836 {
1837 for (int i = 0; i < QUIT_SEND_COUNT; ++i)
1838 {
1839 if (i > 0)
1840 {
1841 SDL_Delay(QUIT_SEND_DELAY);
1842 }
1843 msg.reset();
1844 msg.write8(MSG_JOIN_QUIT);
1845 msg.write32(SDL_GetTicks());
1846 send(joinStatus.address);
1847 }
1848 }
1849 }
1850
erasePlayer(std::map<IPaddress,GamePlayer>::iterator it,const std::string & reason)1851 void Network::erasePlayer(std::map<IPaddress, GamePlayer>::iterator it, const std::string& reason)
1852 {
1853 GamePlayer& gp = it->second;
1854 std::vector<NetworkRaceCar>::iterator carIt;
1855 for (carIt = gp.cars.begin(); carIt != gp.cars.end();)
1856 {
1857 carIt = eraseCar(carIt, reason);
1858 }
1859 gameClients.erase(it);
1860 }
1861
eraseCar(std::vector<NetworkRaceCar>::iterator carIt,const std::string & reason)1862 std::vector<NetworkRaceCar>::iterator Network::eraseCar(std::vector<NetworkRaceCar>::iterator carIt, const std::string& reason)
1863 {
1864 assert(connectionType == NET_GAME_OWNER);
1865 if (carIt->id >= 0)
1866 {
1867 if (gameStateId == NETWORK_GAME_STATE_RACE)
1868 {
1869 for (std::size_t i = 0; i < TRACK_BUFFER_SIZE; ++i)
1870 {
1871 trackStateBuffer[i].removeCar(carIt->id, track->getCarCount());
1872 }
1873 for (std::size_t i = 0; i < INPUT_BUFFER_SIZE; ++i)
1874 {
1875 Uint32 highMask = ~0U << ((carIt->id + 1) * 4);
1876 Uint32 lowMask = ~(~0U << (carIt->id * 4));
1877
1878 Uint32 highInput = (inputBuffer[i] & highMask) >> 4;
1879 Uint32 lowInput = inputBuffer[i] & lowMask;
1880
1881 inputBuffer[i] = highInput | lowInput;
1882 }
1883 track->removeCar(carIt->id);
1884 removedCars.push_back(carIt->id);
1885 }
1886
1887 raceCars.erase(raceCars.begin() + carIt->id);
1888 for (std::size_t i = carIt->id; i < raceCars.size(); ++i)
1889 {
1890 Uint32* mask;
1891 if (raceCars[i]->player)
1892 {
1893 mask = &raceCars[i]->player->inputMask;
1894 }
1895 else
1896 {
1897 mask = &inputMask;
1898 }
1899 *mask &= ~(0xF << (raceCars[i]->id * 4)); // remove old mask
1900 --raceCars[i]->id;
1901 *mask |= 0xF << (raceCars[i]->id * 4); // add new mask
1902 }
1903 }
1904
1905 std::string quitMessage = carIt->name + " has quit!";
1906 if (!reason.empty())
1907 {
1908 quitMessage += " (" + reason + ")";
1909 }
1910 sendChatMessage(quitMessage, carIt->car);
1911 reservedCars &= ~(1 << carIt->car);
1912 --reservedPlayers;
1913
1914 std::vector<NetworkRaceCar>::iterator nextIt;
1915 if (carIt->player)
1916 {
1917 carIt->player->removedCars.push_back(carIt->car);
1918 nextIt = carIt->player->cars.erase(carIt);
1919 }
1920 else
1921 {
1922 chatInput.removePlayer(carIt->car);
1923 nextIt = localCars.erase(carIt);
1924 }
1925
1926 // The pointers need to be reinitialized because some
1927 // of the old pointers might not be valid any more.
1928 for (std::size_t i = 0; i < localCars.size(); ++i)
1929 {
1930 if (localCars[i].id >= 0)
1931 {
1932 raceCars[localCars[i].id] = &localCars[i];
1933 }
1934 }
1935 std::map<IPaddress, GamePlayer>::iterator it;
1936 for (it = gameClients.begin(); it != gameClients.end(); ++it)
1937 {
1938 GamePlayer& gp = it->second;
1939 std::vector<NetworkRaceCar>& nrc = gp.cars;
1940 for (std::size_t i = 0; i < nrc.size(); ++i)
1941 {
1942 if (nrc[i].id >= 0)
1943 {
1944 raceCars[nrc[i].id] = &nrc[i];
1945 }
1946 }
1947 }
1948
1949 return nextIt;
1950 }
1951
eraseCar(int carId)1952 void Network::eraseCar(int carId)
1953 {
1954 assert(connectionType == NET_GAME_PLAYER);
1955
1956 if (gameStateId == NETWORK_GAME_STATE_RACE && carId < track->getCarCount())
1957 {
1958 track->removeCar(carId);
1959 for (std::size_t i = 0; i < INPUT_BUFFER_SIZE; ++i)
1960 {
1961 Uint32 highMask = ~0U << ((carId + 1) * 4);
1962 Uint32 lowMask = ~(~0U << (carId * 4));
1963
1964 Uint32 highInput = (inputBuffer[i] & highMask) >> 4;
1965 Uint32 lowInput = inputBuffer[i] & lowMask;
1966
1967 inputBuffer[i] = highInput | lowInput;
1968 }
1969
1970 inputMask = 0;
1971 std::vector<NetworkRaceCar>::iterator carIt;
1972 for (carIt = localCars.begin(); carIt != localCars.end();)
1973 {
1974 if (carIt->id == carId)
1975 {
1976 carIt = localCars.erase(carIt);
1977 }
1978 else
1979 {
1980 if (carIt->id > carId)
1981 {
1982 --carIt->id;
1983 }
1984 inputMask |= 0xF << (carIt->id * 4);
1985 ++carIt;
1986 }
1987 }
1988 }
1989 }
1990
writeChatMessage()1991 void Network::writeChatMessage()
1992 {
1993 msg.write32(lastChatMessageRecivedFromGameOwner);
1994 if (!chatBuffer.empty() && lastChatMessageDeliveredToGameOwner < lastChatMessage)
1995 {
1996 Uint32 messageToSend = std::max(lastChatMessageDeliveredToGameOwner, static_cast<Uint32>(lastChatMessage - chatBuffer.size())) + 1;
1997 msg.write32(messageToSend);
1998 SentChatMessage& message = chatBuffer[lastChatMessage - messageToSend];
1999 msg.writeString(message.text);
2000 msg.write8(message.car);
2001 }
2002 else
2003 {
2004 msg.write32(0);
2005 }
2006 }
writeChatMessage(const GamePlayer & gp)2007 void Network::writeChatMessage(const GamePlayer& gp)
2008 {
2009 msg.write32(gp.lastChatMessageRecived);
2010 if (!chatBuffer.empty() && gp.lastChatMessageDelivered < lastChatMessage)
2011 {
2012 Uint32 messageToSend = std::max(gp.lastChatMessageDelivered, static_cast<Uint32>(lastChatMessage - chatBuffer.size())) + 1;
2013 msg.write32(messageToSend);
2014 SentChatMessage& message = chatBuffer[lastChatMessage - messageToSend];
2015 msg.writeString(message.text);
2016 msg.write8(message.car);
2017 }
2018 else
2019 {
2020 msg.write32(0);
2021
2022 // send removed cars so that they can be removed from chat list.
2023 msg.write8(gp.removedCars.size());
2024 for (std::size_t i = 0; i < gp.removedCars.size(); ++i)
2025 {
2026 msg.write8(gp.removedCars[i]);
2027 }
2028 }
2029 }
readChatMessage(GamePlayer & gp)2030 void Network::readChatMessage(GamePlayer& gp)
2031 {
2032 Uint32 lastChatMessageDelivered = msg.read32();
2033 if (lastChatMessageDelivered > gp.lastChatMessageDelivered)
2034 {
2035 gp.lastChatMessageDelivered = lastChatMessageDelivered;
2036 }
2037 Uint32 chatMessage = msg.read32();
2038 if (chatMessage != 0 && chatMessage > gp.lastChatMessageRecived)
2039 {
2040 gp.lastChatMessageRecived = chatMessage;
2041 std::string message = msg.readString();
2042 int car = msg.read8();
2043
2044 if (!gp.mute)
2045 {
2046 // Make sure the car is valid.
2047 for (std::size_t i = 0; i < gp.cars.size(); ++i)
2048 {
2049 if (gp.cars[i].car == car)
2050 {
2051 sendChatMessage(message, car);
2052 break;
2053 }
2054 }
2055 }
2056 }
2057 }
readChatMessage()2058 bool Network::readChatMessage()
2059 {
2060 Uint32 lastChatMessageDelivered = msg.read32();
2061 if (lastChatMessageDelivered > lastChatMessageDeliveredToGameOwner)
2062 {
2063 lastChatMessageDeliveredToGameOwner = lastChatMessageDelivered;
2064 }
2065 Uint32 chatMessage = msg.read32();
2066 if (chatMessage != 0)
2067 {
2068 if (chatMessage > lastChatMessageRecivedFromGameOwner)
2069 {
2070 lastChatMessageRecivedFromGameOwner = chatMessage;
2071 std::string message = msg.readString();
2072 int car = msg.read8();
2073 chat.addMessage(message, carColor(car));
2074 }
2075 // Return true even if the chat message has already been received
2076 // so that we can act properly in order to inform the game owner
2077 // that we have received this message.
2078 return true;
2079 }
2080 else
2081 {
2082 // Remove cars from char input list.
2083 int n = msg.read8();
2084 for (int i = 0; i < n; ++i)
2085 {
2086 chatInput.removePlayer(msg.read8());
2087 if (chatInput.empty())
2088 {
2089 setNewGameState(new ErrorState("End of game", "You have been kicked out!", new NetworkMenu(this)));
2090 }
2091 }
2092 }
2093 return false;
2094 }
2095
uniqueName(const std::string & name) const2096 std::string Network::uniqueName(const std::string& name) const
2097 {
2098 std::vector<std::string> names;
2099
2100 std::vector<NetworkRaceCar>::const_iterator itCar;
2101 for (itCar = localCars.begin(); itCar != localCars.end(); ++itCar)
2102 {
2103 names.push_back(itCar->name);
2104 }
2105
2106 std::map<IPaddress, GamePlayer>::const_iterator itPlayer;
2107 for (itPlayer = gameClients.begin(); itPlayer != gameClients.end(); ++itPlayer)
2108 {
2109 const GamePlayer& gp = itPlayer->second;
2110 for (itCar = gp.cars.begin(); itCar != gp.cars.end(); ++itCar)
2111 {
2112 names.push_back(itCar->name);
2113 }
2114 }
2115
2116 std::string uName = name.empty() ? "noname" : name;
2117 int n = 1;
2118 while (std::find(names.begin(), names.end(), uName) != names.end())
2119 {
2120 uName = name + "-" + int2string(++n);
2121 }
2122 return uName;
2123 }
2124
lobby()2125 void Network::lobby()
2126 {
2127 if (connectionType != NET_LOBBY)
2128 {
2129 chat.clear();
2130 chatInput.clear();
2131 chatBuffer.clear();
2132 chatInput.addDefaultPlayers();
2133 }
2134 if (connectionType == NET_GAME_PLAYER)
2135 {
2136 // Let GAME_PLAYER refresh it's list if needed.
2137 refreshAsNeeded();
2138 }
2139
2140 connectionType = NET_LOBBY;
2141 reservedCars = 0;
2142 joinStatus = JoinStatus();
2143 gameStateId = 0;
2144 gameStateCount = 0;
2145 lastGameTimestamp = 0;
2146 lastGameSent = 0;
2147 track = 0;
2148 lastChatMessageDeliveredToGameOwner = 0;
2149 lastChatMessageRecivedFromGameOwner = 0;
2150 }
2151
numberOfPlayersWaiting() const2152 int Network::numberOfPlayersWaiting() const
2153 {
2154 int playerCount = 0;
2155 std::map<IPaddress, Connection>::const_iterator it;
2156
2157 for (it = connections.begin(); it != connections.end(); ++it)
2158 {
2159 const Connection& connection = it->second;
2160 if (!connection.isBot && connection.gameInfo == 0)
2161 {
2162 ++playerCount;
2163 }
2164 }
2165
2166 return playerCount;
2167 }
2168