source: network-game/server/server.cpp@ 7f9b01c

Last change on this file since 7f9b01c was d58e3c3, checked in by Dmitry Portnoy <dmp1488@…>, 10 years ago

When a clients fails to create a game, send a CREATE_GAME_FAILURE message instead of a JOIN_GAME_FAILURE message

  • Property mode set to 100644
File size: 37.4 KB
Line 
1#include <cstdlib>
2#include <cstdio>
3#include <unistd.h>
4#include <string>
5#include <iostream>
6#include <sstream>
7#include <fstream>
8#include <cstring>
9
10#include <vector>
11#include <map>
12
13#include <csignal>
14
15#include <sys/time.h>
16
17#include <sys/socket.h>
18#include <netdb.h>
19#include <netinet/in.h>
20#include <arpa/inet.h>
21
22#include <crypt.h>
23
24/*
25#include <openssl/bio.h>
26#include <openssl/ssl.h>
27#include <openssl/err.h>
28*/
29
30#include "../common/Compiler.h"
31#include "../common/Common.h"
32#include "../common/MessageProcessor.h"
33#include "../common/WorldMap.h"
34#include "../common/Player.h"
35#include "../common/Projectile.h"
36#include "../common/Game.h"
37#include "../common/GameSummary.h"
38
39#include "DataAccess.h"
40
41using namespace std;
42
43// from used to be const. Removed that so I could take a reference
44// and use it to send messages
45void processMessage(const NETWORK_MSG& clientMsg, struct sockaddr_in& from, MessageProcessor& msgProcessor, map<unsigned int, Player*>& mapPlayers, map<string, Game*>& mapGames, DataAccess& da, ofstream& outputLog);
46
47Player *findPlayerByName(map<unsigned int, Player*> &m, string name);
48Player *findPlayerByAddr(map<unsigned int, Player*> &m, const sockaddr_in &addr);
49
50bool handleGameEvents(Game* game, MessageProcessor* msgProcessor, DataAccess* da);
51bool handlePlayerEvents(Game* game, Player* p, MessageProcessor* msgProcessor, DataAccess* da);
52
53void quit(int sig);
54
55bool done;
56
57int main(int argc, char *argv[])
58{
59 int sock, length;
60 struct sockaddr_in server;
61 struct sockaddr_in from; // info of client sending the message
62 NETWORK_MSG clientMsg, serverMsg;
63 MessageProcessor msgProcessor;
64 map<unsigned int, Player*> mapPlayers;
65 map<unsigned int, Projectile> mapProjectiles;
66 map<string, Game*> mapGames;
67 DataAccess da;
68 ofstream outputLog;
69
70 done = false;
71
72 signal(SIGINT, quit);
73
74 //SSL_load_error_strings();
75 //ERR_load_BIO_strings();
76 //OpenSSL_add_all_algorithms();
77
78 if (argc != 2)
79 {
80 cerr << "ERROR, expected server [domain] [port]" << endl;
81 exit(1);
82 }
83
84 outputLog.open("server.log", ios::app);
85 outputLog << "Started server on " << getCurrentDateTimeString() << endl;
86
87 sock = socket(AF_INET, SOCK_DGRAM, 0);
88 if (sock < 0)
89 error("Opening socket");
90 length = sizeof(server);
91 bzero(&server,length);
92 server.sin_family=AF_INET;
93 server.sin_port=htons(atoi(argv[1]));
94 server.sin_addr.s_addr=INADDR_ANY;
95 if ( bind(sock, (struct sockaddr *)&server, length) < 0 )
96 error("binding");
97
98 set_nonblock(sock);
99
100 msgProcessor = MessageProcessor(sock, &outputLog);
101
102 timespec ts;
103 int timeLastUpdated = 0, curTime = 0;
104 while (!done)
105 {
106 usleep(5000);
107
108 clock_gettime(CLOCK_REALTIME, &ts);
109 // make the number smaller so millis can fit in an int
110 ts.tv_sec -= 1368000000;
111 curTime = ts.tv_sec*1000 + ts.tv_nsec/1000000;
112
113 if (timeLastUpdated == 0 || (curTime-timeLastUpdated) >= 50)
114 {
115 timeLastUpdated = curTime;
116
117 msgProcessor.cleanAckedMessages();
118 msgProcessor.resendUnackedMessages();
119
120 map<unsigned int, Player*>::iterator it;
121
122 // set targets for all chasing players (or make them attack if they're close enough)
123 // this should be moved into the games loop
124 for (it = mapPlayers.begin(); it != mapPlayers.end(); it++)
125 {
126 Player* p = it->second;
127
128 // check if it's time to revive dead players
129 if (p->isDead)
130 {
131 cout << "Player is dead" << endl;
132
133 if (getCurrentMillis() - p->timeDied >= 10000)
134 {
135 p->isDead = false;
136
137 POSITION spawnPos;
138
139 switch (p->team)
140 {
141 case Player::TEAM_BLUE:
142 spawnPos = p->currentGame->getMap()->getStructureLocation(STRUCTURE_BLUE_FLAG);
143 break;
144 case Player::TEAM_RED:
145 spawnPos = p->currentGame->getMap()->getStructureLocation(STRUCTURE_RED_FLAG);
146 break;
147 default:
148 // should never go here
149 cout << "Error: Invalid team" << endl;
150 break;
151 }
152
153 // spawn the player to the right of their flag location
154 spawnPos.x = (spawnPos.x+1) * 25 + 12;
155 spawnPos.y = spawnPos.y * 25 + 12;
156
157 p->pos = spawnPos.toFloat();
158 p->target = spawnPos;
159 p->health = p->maxHealth;
160
161 serverMsg.type = MSG_TYPE_PLAYER;
162 p->serialize(serverMsg.buffer);
163
164 msgProcessor.broadcastMessage(serverMsg, p->currentGame->getPlayers());
165 }
166
167 continue;
168 }
169
170 if (p->currentGame != NULL) {
171 map<unsigned int, Player*> playersInGame = p->currentGame->getPlayers();
172 if (p->updateTarget(playersInGame))
173 {
174 serverMsg.type = MSG_TYPE_PLAYER;
175 p->serialize(serverMsg.buffer);
176 msgProcessor.broadcastMessage(serverMsg, playersInGame);
177 }
178 }
179 }
180
181 // process players currently in a game
182 map<string, Game*>::iterator itGames;
183 Game* game = NULL;
184
185 for (itGames = mapGames.begin(); itGames != mapGames.end();) {
186 game = itGames->second;
187 bool gameFinished = handleGameEvents(game, &msgProcessor, &da);
188
189 if (gameFinished) {
190 // save game record
191 int winningTeam = -1;
192 if (game->getBlueScore() == 3)
193 winningTeam = 1;
194 else if (game->getRedScore() == 3)
195 winningTeam = 2;
196
197 if (winningTeam == -1)
198 cout << "Error: Game ended, but neither team has a score of 3" << endl;
199 else {
200 map<unsigned int, Player*>::iterator it;
201
202 time_t timeFinished = time(NULL);
203 for (it = game->getPlayers().begin(); it != game->getPlayers().end(); it++) {
204 Player* p = it->second;
205 cout << "winning team: " << winningTeam << endl;
206 cout << "player team: " << p->team << endl;
207 cout << "player id: " << p->getId() << endl;
208
209 if (winningTeam == p->team)
210 p->wins++;
211 else
212 p->losses++;
213 da.updatePlayer(p);
214 da.saveGameHistory(p->getId(), winningTeam, game->getBlueScore(), game->getRedScore(), timeFinished);
215 }
216 }
217
218 // send a GAME_INFO message with 0 players to force clients to delete the game
219 int numPlayers = 0;
220 serverMsg.type = MSG_TYPE_GAME_INFO;
221 memcpy(serverMsg.buffer, &numPlayers, 4);
222 strcpy(serverMsg.buffer+4, game->getName().c_str());
223
224 // only send this to players in the game
225 msgProcessor.broadcastMessage(serverMsg, game->getPlayers());
226
227 delete itGames->second;
228 mapGames.erase(itGames++);
229 }else
230 itGames++;
231 }
232
233 // move all projectiles
234 // see if this can be moved inside the game class
235 // this method can be moved when I add a MessageProcessor to the Game class
236 map<unsigned int, Projectile>::iterator itProj;
237 for (itGames = mapGames.begin(); itGames != mapGames.end(); itGames++) {
238 game = itGames->second;
239 for (itProj = game->getProjectiles().begin(); itProj != game->getProjectiles().end(); itProj++)
240 {
241 cout << "About to call projectile move" << endl;
242 if (itProj->second.move(game->getPlayers()))
243 {
244 // send a REMOVE_PROJECTILE message
245 cout << "send a REMOVE_PROJECTILE message" << endl;
246 serverMsg.type = MSG_TYPE_REMOVE_PROJECTILE;
247 memcpy(serverMsg.buffer, &itProj->second.id, 4);
248 game->removeProjectile(itProj->second.id);
249 msgProcessor.broadcastMessage(serverMsg, game->getPlayers());
250
251 Player* target = game->getPlayers()[itProj->second.target];
252 game->dealDamageToPlayer(target, itProj->second.damage);
253 }
254 }
255 }
256 }
257
258 if (msgProcessor.receiveMessage(&clientMsg, &from) >= 0)
259 {
260 processMessage(clientMsg, from, msgProcessor, mapPlayers, mapGames, da, outputLog);
261
262 cout << "Finished processing the message" << endl;
263 }
264 }
265
266 outputLog << "Stopped server on " << getCurrentDateTimeString() << endl;
267 outputLog.close();
268
269 // delete all games
270 map<string, Game*>::iterator itGames;
271 for (itGames = mapGames.begin(); itGames != mapGames.end(); itGames++)
272 {
273 delete itGames->second;
274 }
275
276 map<unsigned int, Player*>::iterator itPlayers;
277 for (itPlayers = mapPlayers.begin(); itPlayers != mapPlayers.end(); itPlayers++)
278 {
279 delete itPlayers->second;
280 }
281
282 return 0;
283}
284
285void processMessage(const NETWORK_MSG &clientMsg, struct sockaddr_in &from, MessageProcessor &msgProcessor, map<unsigned int, Player*>& mapPlayers, map<string, Game*>& mapGames, DataAccess& da, ofstream& outputLog)
286{
287 NETWORK_MSG serverMsg;
288
289 cout << "Inside processMessage" << endl;
290
291 cout << "Received message" << endl;
292 cout << "MSG: type: " << clientMsg.type << endl;
293 cout << "MSG contents: " << clientMsg.buffer << endl;
294
295 // Check that if an invalid message is sent, the client will correctly
296 // receive and display the response. Maybe make a special error msg type
297 switch(clientMsg.type)
298 {
299 case MSG_TYPE_REGISTER:
300 {
301 string username(clientMsg.buffer);
302 string password(strchr(clientMsg.buffer, '\0')+1);
303 Player::PlayerClass playerClass;
304
305 memcpy(&playerClass, clientMsg.buffer+username.length()+password.length()+2, 4);
306
307 cout << "username: " << username << endl;
308 cout << "password: " << password << endl;
309
310 bool validClass = false;
311
312 switch(playerClass) {
313 case Player::CLASS_WARRIOR:
314 case Player::CLASS_RANGER:
315 validClass = true;
316 break;
317 case Player::CLASS_NONE:
318 validClass = false;
319 break;
320 }
321
322 serverMsg.type = MSG_TYPE_REGISTER;
323
324 if (validClass) {
325 int error = da.insertPlayer(username, password, playerClass);
326
327 if (error)
328 strcpy(serverMsg.buffer, "Registration failed. Please try again.");
329 else
330 strcpy(serverMsg.buffer, "Registration successful.");
331 }else
332 strcpy(serverMsg.buffer, "You didn't select a class");
333
334 msgProcessor.sendMessage(&serverMsg, &from);
335
336 break;
337 }
338 case MSG_TYPE_LOGIN:
339 {
340 cout << "Got login message" << endl;
341
342 string username(clientMsg.buffer);
343 string password(strchr(clientMsg.buffer, '\0')+1);
344
345 Player* p = da.getPlayer(username);
346
347 if (p == NULL || !da.verifyPassword(password, p->password))
348 {
349 strcpy(serverMsg.buffer, "Incorrect username or password");
350 if (p != NULL)
351 delete(p);
352 }
353 else if(findPlayerByName(mapPlayers, username) != NULL)
354 {
355 strcpy(serverMsg.buffer, "Player has already logged in.");
356 delete(p);
357 }
358 else
359 {
360 cout << "new player id: " << p->getId() << endl;
361 p->setAddr(from);
362
363 serverMsg.type = MSG_TYPE_PLAYER;
364 // tell the new player about all the existing players
365 cout << "Sending other players to new player" << endl;
366
367 map<unsigned int, Player*>::iterator it;
368 for (it = mapPlayers.begin(); it != mapPlayers.end(); it++)
369 {
370 it->second->serialize(serverMsg.buffer);
371
372 cout << "sending info about " << it->second->name << endl;
373 cout << "sending id " << it->second->getId() << endl;
374 msgProcessor.sendMessage(&serverMsg, &from);
375 }
376
377 // send info about existing games to new player
378 map<string, Game*>::iterator itGames;
379 Game* g;
380 int numPlayers;
381 serverMsg.type = MSG_TYPE_GAME_INFO;
382
383 for (itGames = mapGames.begin(); itGames != mapGames.end(); itGames++)
384 {
385 g = itGames->second;
386 numPlayers = g->getNumPlayers();
387 memcpy(serverMsg.buffer, &numPlayers, 4);
388 strcpy(serverMsg.buffer+4, g->getName().c_str());
389 msgProcessor.sendMessage(&serverMsg, &from);
390 }
391
392 serverMsg.type = MSG_TYPE_PLAYER;
393 p->serialize(serverMsg.buffer);
394 msgProcessor.broadcastMessage(serverMsg, mapPlayers);
395
396 mapPlayers[p->getId()] = p;
397 }
398
399 serverMsg.type = MSG_TYPE_LOGIN;
400 msgProcessor.sendMessage(&serverMsg, &from);
401
402 break;
403 }
404 case MSG_TYPE_LOGOUT:
405 {
406 string name(clientMsg.buffer);
407 cout << "Player logging out: " << name << endl;
408
409 Player *p = findPlayerByName(mapPlayers, name);
410
411 if (p == NULL)
412 {
413 strcpy(serverMsg.buffer+4, "That player is not logged in. This is either a bug, or you're trying to hack the server.");
414 cout << "Player not logged in" << endl;
415 }
416 else if ( p->addr.sin_addr.s_addr != from.sin_addr.s_addr ||
417 p->addr.sin_port != from.sin_port )
418 {
419 strcpy(serverMsg.buffer+4, "That player is logged in using a differemt connection. This is either a bug, or you're trying to hack the server.");
420 cout << "Player logged in using a different connection" << endl;
421 }
422 else
423 {
424 // broadcast to all players before deleting p from the map
425 unsigned int playerId = p->getId();
426 serverMsg.type = MSG_TYPE_LOGOUT;
427 memcpy(serverMsg.buffer, &playerId, 4);
428
429 msgProcessor.broadcastMessage(serverMsg, mapPlayers);
430
431 mapPlayers.erase(p->getId());
432 delete p;
433
434 strcpy(serverMsg.buffer+4, "You have successfully logged out.");
435 }
436
437 serverMsg.type = MSG_TYPE_LOGOUT;
438 msgProcessor.sendMessage(&serverMsg, &from);
439
440 break;
441 }
442 case MSG_TYPE_CHAT:
443 {
444 cout << "Got a chat message" << endl;
445
446 serverMsg.type = MSG_TYPE_CHAT;
447
448 Player *p = findPlayerByAddr(mapPlayers, from);
449
450 if (p == NULL)
451 {
452 strcpy(serverMsg.buffer, "No player is logged in using this connection. This is either a bug, or you're trying to hack the server.");
453 msgProcessor.sendMessage(&serverMsg, &from);
454 }
455 else
456 {
457 ostringstream oss;
458 oss << p->name << ": " << clientMsg.buffer;
459
460 strcpy(serverMsg.buffer, oss.str().c_str());
461 msgProcessor.broadcastMessage(serverMsg, mapPlayers);
462 }
463
464 break;
465 }
466 case MSG_TYPE_PLAYER_MOVE:
467 {
468 cout << "PLAYER_MOVE" << endl;
469
470 unsigned int id;
471 int x, y;
472
473 memcpy(&id, clientMsg.buffer, 4);
474 memcpy(&x, clientMsg.buffer+4, 4);
475 memcpy(&y, clientMsg.buffer+8, 4);
476
477 cout << "x: " << x << endl;
478 cout << "y: " << y << endl;
479 cout << "id: " << id << endl;
480
481 Player* p = mapPlayers[id];
482 bool validMessage = false;
483
484 if ( p->addr.sin_addr.s_addr == from.sin_addr.s_addr &&
485 p->addr.sin_port == from.sin_port )
486 {
487 if (p->currentGame->startPlayerMovement(id, x, y)) {
488 serverMsg.type = MSG_TYPE_PLAYER_MOVE;
489
490 memcpy(serverMsg.buffer, &id, 4);
491 memcpy(serverMsg.buffer+4, &p->target.x, 4);
492 memcpy(serverMsg.buffer+8, &p->target.y, 4);
493
494 msgProcessor.broadcastMessage(serverMsg, mapPlayers);
495
496 validMessage = true;
497 }
498 else
499 cout << "Bad terrain detected" << endl;
500 }
501 else
502 cout << "Player id (" << id << ") doesn't match sender" << endl;
503
504 if (!validMessage)
505 msgProcessor.sendMessage(&serverMsg, &from);
506
507 break;
508 }
509 case MSG_TYPE_PICKUP_FLAG:
510 {
511 // may want to check the id matches the sender, just like for PLAYER_NOVE
512 cout << "PICKUP_FLAG" << endl;
513
514 unsigned int id;
515
516 memcpy(&id, clientMsg.buffer, 4);
517 cout << "id: " << id << endl;
518
519 Player* p = mapPlayers[id];
520 unsigned int objectId = p->currentGame->processFlagPickupRequest(p);
521
522 if (objectId >= 0) {
523 map<unsigned int, Player*> players = p->currentGame->getPlayers();
524
525 serverMsg.type = MSG_TYPE_REMOVE_OBJECT;
526 memcpy(serverMsg.buffer, &objectId, 4);
527 msgProcessor.broadcastMessage(serverMsg, players);
528
529 serverMsg.type = MSG_TYPE_PLAYER;
530 p->serialize(serverMsg.buffer);
531 msgProcessor.broadcastMessage(serverMsg, players);
532 }
533
534 break;
535 }
536 case MSG_TYPE_DROP_FLAG:
537 {
538 // may want to check the id matches the sender, just like for PLAYER_NOVE
539 cout << "DROP_FLAG" << endl;
540
541 unsigned int id;
542
543 memcpy(&id, clientMsg.buffer, 4);
544 cout << "id: " << id << endl;
545
546 Player* p = mapPlayers[id];
547
548 ObjectType flagType = OBJECT_NONE;
549 if (p->hasBlueFlag)
550 flagType = OBJECT_BLUE_FLAG;
551 else if (p->hasRedFlag)
552 flagType = OBJECT_RED_FLAG;
553
554 map<unsigned int, Player*> players = p->currentGame->getPlayers();
555
556 p->currentGame->addObjectToMap(flagType, p->pos.x, p->pos.y);
557
558 p->hasBlueFlag = false;
559 p->hasRedFlag = false;
560
561 serverMsg.type = MSG_TYPE_PLAYER;
562 p->serialize(serverMsg.buffer);
563 msgProcessor.broadcastMessage(serverMsg, players);
564
565 break;
566 }
567 case MSG_TYPE_ATTACK:
568 {
569 cout << "Received a START_ATTACK message" << endl;
570
571 unsigned int id, targetId;
572
573 memcpy(&id, clientMsg.buffer, 4);
574 memcpy(&targetId, clientMsg.buffer+4, 4);
575
576 // need to make sure the target is in the sender's game
577
578 Player* p = mapPlayers[id];
579 p->setTargetPlayer(targetId);
580 p->isChasing = true;
581
582 map<unsigned int, Player*> players = p->currentGame->getPlayers();
583
584 serverMsg.type = MSG_TYPE_ATTACK;
585 memcpy(serverMsg.buffer, &id, 4);
586 memcpy(serverMsg.buffer+4, &targetId, 4);
587 msgProcessor.broadcastMessage(serverMsg, players);
588
589 break;
590 }
591 case MSG_TYPE_PROFILE:
592 {
593 cout << "Received a PROFILE message" << endl;
594
595 unsigned int id;
596
597 memcpy(&id, clientMsg.buffer, 4);
598
599 cout << "Player id: " << id << endl;
600 unsigned int numGames = 0;
601 int** gameHistory = da.getPlayerGameHistory(id, numGames);
602 int* playerRecord = da.getPlayerRecord(id);
603
604 // playerRecord[0] is level
605 // playerRecord[1] is experience
606 int honorPoints = playerRecord[2];
607 int wins = playerRecord[3];
608 int losses = playerRecord[4];
609
610 serverMsg.type = MSG_TYPE_PROFILE;
611
612 memcpy(serverMsg.buffer, &honorPoints, 4);
613 memcpy(serverMsg.buffer+4, &wins, 4);
614 memcpy(serverMsg.buffer+8, &losses, 4);
615 memcpy(serverMsg.buffer+12, &numGames, 4);
616 for (unsigned int i=0; i<numGames; i++) {
617 memcpy(serverMsg.buffer+16+i*20, &gameHistory[i][0], 4);
618 memcpy(serverMsg.buffer+20+i*20, &gameHistory[i][1], 4);
619 memcpy(serverMsg.buffer+24+i*20, &gameHistory[i][2], 4);
620 memcpy(serverMsg.buffer+28+i*20, &gameHistory[i][3], 4);
621 memcpy(serverMsg.buffer+32+i*20, &gameHistory[i][4], 4);
622 delete[] gameHistory[i];
623 }
624
625 //delete[] gameHistory;
626 free(gameHistory);
627 delete[] playerRecord;
628
629 msgProcessor.sendMessage(&serverMsg, &from);
630
631 break;
632 }
633 case MSG_TYPE_CREATE_GAME:
634 {
635 cout << "Received a CREATE_GAME message" << endl;
636
637 string gameName(clientMsg.buffer);
638 cout << "Game name: " << gameName << endl;
639
640 // check if this game already exists
641 if (mapGames.find(gameName) != mapGames.end()) {
642 cout << "Error: Game already exists" << endl;
643 serverMsg.type = MSG_TYPE_CREATE_GAME_FAILURE;
644 }else {
645 Game* g = new Game(gameName, "../data/map.txt", &msgProcessor);
646 mapGames[gameName] = g;
647
648 // add flag objects to the map
649 WorldMap* m = g->getMap();
650 m->createObjectsFromStructures();
651
652 serverMsg.type = MSG_TYPE_JOIN_GAME_SUCCESS;
653 strcpy(serverMsg.buffer, gameName.c_str());
654 }
655
656 msgProcessor.sendMessage(&serverMsg, &from);
657
658 break;
659 }
660 case MSG_TYPE_JOIN_GAME:
661 {
662 cout << "Received a JOIN_GAME message" << endl;
663
664 string gameName(clientMsg.buffer);
665 cout << "Game name: " << gameName << endl;
666
667 // check if this game already exists
668 if (mapGames.find(gameName) == mapGames.end()) {
669 cout << "Error: Game does not exist" << endl;
670 serverMsg.type = MSG_TYPE_JOIN_GAME_FAILURE;
671 }else {
672 Game* g = mapGames[gameName];
673 map<unsigned int, Player*>& players = g->getPlayers();
674 Player* p = findPlayerByAddr(mapPlayers, from);
675
676 if (players.find(p->getId()) != players.end()) {
677 cout << "Player " << p->name << " trying to join a game he's already in" << endl;
678 serverMsg.type = MSG_TYPE_JOIN_GAME_FAILURE;
679 }else {
680 serverMsg.type = MSG_TYPE_JOIN_GAME_SUCCESS;
681 strcpy(serverMsg.buffer, gameName.c_str());
682 }
683 }
684
685 msgProcessor.sendMessage(&serverMsg, &from);
686
687 break;
688 }
689 case MSG_TYPE_LEAVE_GAME:
690 {
691 cout << "Received a LEAVE_GAME message" << endl;
692
693 Player* p = findPlayerByAddr(mapPlayers, from);
694 Game* g = p->currentGame;
695
696 if (g == NULL) {
697 cout << "Player " << p->name << " is trying to leave a game, but is not currently in a game." << endl;
698
699 /// should send a response back, maybe a new message type is needed
700 // not sure what to do here
701 }else {
702 cout << "Game name: " << g->getName() << endl;
703
704 if (!p->isDead) {
705 ObjectType flagType = OBJECT_NONE;
706 if (p->hasBlueFlag)
707 flagType = OBJECT_BLUE_FLAG;
708 else if (p->hasRedFlag)
709 flagType = OBJECT_RED_FLAG;
710
711 if (flagType != OBJECT_NONE)
712 g->addObjectToMap(flagType, p->pos.x, p->pos.y);
713 }
714
715 p->currentGame = NULL;
716 g->removePlayer(p->getId());
717
718 unsigned int playerId = p->getId();
719 serverMsg.type = MSG_TYPE_LEAVE_GAME;
720 memcpy(serverMsg.buffer, &playerId, 4);
721 strcpy(serverMsg.buffer+4, g->getName().c_str());
722 msgProcessor.broadcastMessage(serverMsg, g->getPlayers());
723
724 int numPlayers = g->getNumPlayers();
725
726 serverMsg.type = MSG_TYPE_GAME_INFO;
727 memcpy(serverMsg.buffer, &numPlayers, 4);
728 strcpy(serverMsg.buffer+4, g->getName().c_str());
729 msgProcessor.broadcastMessage(serverMsg, mapPlayers);
730
731 // if there are no more players in the game, remove it
732 if (numPlayers == 0) {
733 mapGames.erase(g->getName());
734 delete g;
735 }
736 }
737
738 break;
739 }
740 case MSG_TYPE_JOIN_GAME_ACK:
741 {
742 cout << "Received a JOIN_GAME_ACK message" << endl;
743
744 string gameName(clientMsg.buffer);
745 cout << "Game name: " << gameName << endl;
746
747 // check if this game already exists
748 if (mapGames.find(gameName) == mapGames.end()) {
749 serverMsg.type = MSG_TYPE_JOIN_GAME_FAILURE;
750
751 msgProcessor.sendMessage(&serverMsg, &from);
752 }
753
754 Game* g = mapGames[gameName];
755
756 Player* p = findPlayerByAddr(mapPlayers, from);
757
758 // tell the new player about all map objects
759 // (currently just the flags)
760
761 serverMsg.type = MSG_TYPE_OBJECT;
762 vector<WorldMap::Object>* vctObjects = g->getMap()->getObjects();
763 vector<WorldMap::Object>::iterator itObjects;
764 cout << "sending items" << endl;
765 for (itObjects = vctObjects->begin(); itObjects != vctObjects->end(); itObjects++) {
766 itObjects->serialize(serverMsg.buffer);
767 cout << "sending item id " << itObjects->id << endl;
768 msgProcessor.sendMessage(&serverMsg, &from);
769 }
770
771
772 // send the current score
773 serverMsg.type = MSG_TYPE_SCORE;
774
775 unsigned int blueScore = g->getBlueScore();
776 unsigned int redScore = g->getRedScore();
777 memcpy(serverMsg.buffer, &blueScore, 4);
778 memcpy(serverMsg.buffer+4, &redScore, 4);
779
780 msgProcessor.sendMessage(&serverMsg, &from);
781
782
783 map<unsigned int, Player*>& oldPlayers = g->getPlayers();
784 g->addPlayer(p);
785 p->team = Player::TEAM_NONE;
786
787 // send info to other players
788 serverMsg.type = MSG_TYPE_PLAYER_JOIN_GAME;
789 p->serialize(serverMsg.buffer);
790 cout << "Should be broadcasting the message" << endl;
791 msgProcessor.broadcastMessage(serverMsg, oldPlayers);
792
793
794 // tell the new player about all the players in the game (including himself)
795 cout << "Sending other players to new player" << endl;
796 serverMsg.type = MSG_TYPE_PLAYER_JOIN_GAME;
797
798 map<unsigned int, Player*>& allPlayers = g->getPlayers();
799 map<unsigned int, Player*>::iterator it;
800 for (it = allPlayers.begin(); it != allPlayers.end(); it++)
801 {
802 it->second->serialize(serverMsg.buffer);
803
804 cout << "sending info about " << it->second->name << endl;
805 cout << "sending id " << it->second->getId() << endl;
806 msgProcessor.sendMessage(&serverMsg, &from);
807 }
808
809
810 int numPlayers = g->getNumPlayers();
811
812 serverMsg.type = MSG_TYPE_GAME_INFO;
813 memcpy(serverMsg.buffer, &numPlayers, 4);
814 strcpy(serverMsg.buffer+4, gameName.c_str());
815 msgProcessor.broadcastMessage(serverMsg, mapPlayers);
816
817 break;
818 }
819 case MSG_TYPE_JOIN_TEAM:
820 {
821 cout << "Received a JOIN_TEAM message" << endl;
822
823 Player* p = findPlayerByAddr(mapPlayers, from);
824 map<unsigned int, Player*> players = p->currentGame->getPlayers();
825
826 memcpy(&(p->team), clientMsg.buffer, 4);
827
828 serverMsg.type = MSG_TYPE_PLAYER;
829 p->serialize(serverMsg.buffer);
830 msgProcessor.broadcastMessage(serverMsg, players);
831
832 break;
833 }
834 case MSG_TYPE_START_GAME:
835 {
836 cout << "Received a START_GAME message" << endl;
837
838 Player* p = findPlayerByAddr(mapPlayers, from);
839 map<unsigned int, Player*> players = p->currentGame->getPlayers();
840
841 serverMsg.type = MSG_TYPE_START_GAME;
842 msgProcessor.broadcastMessage(serverMsg, players);
843
844 // send a GAME_INFO message to all players not in the game so they delete it from their lobby
845 map<unsigned int, Player*> playersNotInGame;
846 map<unsigned int, Player*>::iterator it;
847
848 for (it = mapPlayers.begin(); it != mapPlayers.end(); it++) {
849 if (players.count(it->first) == 0)
850 playersNotInGame[it->first] = it->second;
851 }
852
853 cout << "Sending game info to " << playersNotInGame.size() << " players not in the currently started game" << endl;
854
855 int numPlayers = 0;
856 serverMsg.type = MSG_TYPE_GAME_INFO;
857 memcpy(serverMsg.buffer, &numPlayers, 4);
858 strcpy(serverMsg.buffer+4, p->currentGame->getName().c_str());
859
860 msgProcessor.broadcastMessage(serverMsg, playersNotInGame);
861
862 break;
863 }
864 default:
865 {
866 outputLog << "Received unknown message of type " << clientMsg.type << endl;
867
868 break;
869 }
870 }
871}
872
873Player *findPlayerByName(map<unsigned int, Player*> &m, string name)
874{
875 map<unsigned int, Player*>::iterator it;
876
877 for (it = m.begin(); it != m.end(); it++)
878 {
879 if ( it->second->name.compare(name) == 0 )
880 return it->second;
881 }
882
883 return NULL;
884}
885
886Player *findPlayerByAddr(map<unsigned int, Player*> &m, const sockaddr_in &addr)
887{
888 map<unsigned int, Player*>::iterator it;
889
890 for (it = m.begin(); it != m.end(); it++)
891 {
892 if ( it->second->addr.sin_addr.s_addr == addr.sin_addr.s_addr &&
893 it->second->addr.sin_port == addr.sin_port )
894 return it->second;
895 }
896
897 return NULL;
898}
899
900bool handleGameEvents(Game* game, MessageProcessor* msgProcessor, DataAccess* da) {
901 map<unsigned int, Player*> players = game->getPlayers();
902 map<unsigned int, Player*>::iterator it;
903 bool gameFinished = false;
904
905 for (it = players.begin(); it != players.end(); it++) {
906 gameFinished = gameFinished || handlePlayerEvents(game, it->second, msgProcessor, da);
907 }
908
909 if (gameFinished) {
910 for (it = players.begin(); it != players.end(); it++) {
911 it->second->currentGame = NULL;
912 }
913 }
914
915 return gameFinished;
916}
917
918bool handlePlayerEvents(Game* game, Player* p, MessageProcessor* msgProcessor, DataAccess* da) {
919 NETWORK_MSG serverMsg;
920 FLOAT_POSITION oldPos;
921 bool gameFinished = false;
922 bool broadcastMove = false;
923
924 cout << "moving player" << endl;
925
926 // move player and perform associated tasks
927 oldPos = p->pos;
928 if (p->move(game->getMap())) {
929
930 cout << "player moved" << endl;
931 if (game->processPlayerMovement(p, oldPos))
932 broadcastMove = true;
933 cout << "player move processed" << endl;
934
935 ObjectType flagType;
936 POSITION pos;
937 bool flagTurnedIn = false;
938 bool flagReturned = false;
939 bool ownFlagAtBase = false;
940
941 switch(game->getMap()->getStructure(p->pos.x/25, p->pos.y/25)) {
942 case STRUCTURE_BLUE_FLAG:
943 {
944 if (p->team == Player::TEAM_BLUE && p->hasRedFlag) {
945 // check that your flag is at your base
946 pos = game->getMap()->getStructureLocation(STRUCTURE_BLUE_FLAG);
947
948 vector<WorldMap::Object>* vctObjects = game->getMap()->getObjects();
949 vector<WorldMap::Object>::iterator itObjects;
950
951 for (itObjects = vctObjects->begin(); itObjects != vctObjects->end(); itObjects++) {
952 if (itObjects->type == OBJECT_BLUE_FLAG) {
953 if (itObjects->pos.x == pos.x*25+12 && itObjects->pos.y == pos.y*25+12) {
954 ownFlagAtBase = true;
955 break;
956 }
957 }
958 }
959
960 if (ownFlagAtBase) {
961 p->hasRedFlag = false;
962 flagType = OBJECT_RED_FLAG;
963 pos = game->getMap()->getStructureLocation(STRUCTURE_RED_FLAG);
964 flagTurnedIn = true;
965 game->setBlueScore(game->getBlueScore()+1);
966 }
967 }
968
969 break;
970 }
971 case STRUCTURE_RED_FLAG:
972 {
973 if (p->team == Player::TEAM_RED && p->hasBlueFlag) {
974 // check that your flag is at your base
975 pos = game->getMap()->getStructureLocation(STRUCTURE_RED_FLAG);
976
977 vector<WorldMap::Object>* vctObjects = game->getMap()->getObjects();
978 vector<WorldMap::Object>::iterator itObjects;
979
980 for (itObjects = vctObjects->begin(); itObjects != vctObjects->end(); itObjects++) {
981 if (itObjects->type == OBJECT_RED_FLAG) {
982 if (itObjects->pos.x == pos.x*25+12 && itObjects->pos.y == pos.y*25+12) {
983 ownFlagAtBase = true;
984 break;
985 }
986 }
987 }
988
989 if (ownFlagAtBase) {
990 p->hasBlueFlag = false;
991 flagType = OBJECT_BLUE_FLAG;
992 pos = game->getMap()->getStructureLocation(STRUCTURE_BLUE_FLAG);
993 flagTurnedIn = true;
994 game->setRedScore(game->getRedScore()+1);
995 }
996 }
997
998 break;
999 }
1000 default:
1001 {
1002 break;
1003 }
1004 }
1005
1006 if (flagTurnedIn) {
1007 unsigned int blueScore = game->getBlueScore();
1008 unsigned int redScore = game->getRedScore();
1009
1010 pos.x = pos.x*25+12;
1011 pos.y = pos.y*25+12;
1012 game->addObjectToMap(flagType, pos.x, pos.y);
1013
1014 serverMsg.type = MSG_TYPE_SCORE;
1015 memcpy(serverMsg.buffer, &blueScore, 4);
1016 memcpy(serverMsg.buffer+4, &redScore, 4);
1017 msgProcessor->broadcastMessage(serverMsg, game->getPlayers());
1018
1019 // give honor to everyone on the winning team
1020 map<unsigned int, Player*>::iterator itPlayers;
1021 for (itPlayers = game->getPlayers().begin(); itPlayers != game->getPlayers().end(); itPlayers++) {
1022 if (itPlayers->second->team == p->team) {
1023 itPlayers->second->honor += 50;
1024 da->updatePlayer(itPlayers->second);
1025 }
1026 }
1027
1028 // check to see if the game should end
1029 // move to its own method
1030 if (game->getBlueScore() == 3 || game->getRedScore() == 3) {
1031 gameFinished = true;
1032
1033 unsigned int winningTeam;
1034 if (game->getBlueScore() == 3)
1035 winningTeam = 0;
1036 else if (game->getRedScore() == 3)
1037 winningTeam = 1;
1038
1039 serverMsg.type = MSG_TYPE_FINISH_GAME;
1040
1041 // I should create an instance of the GameSummary object here and just serialize it into this message
1042 memcpy(serverMsg.buffer, &winningTeam, 4);
1043 memcpy(serverMsg.buffer+4, &blueScore, 4);
1044 memcpy(serverMsg.buffer+8, &redScore, 4);
1045 strcpy(serverMsg.buffer+12, game->getName().c_str());
1046 msgProcessor->broadcastMessage(serverMsg, game->getPlayers());
1047
1048 // give honor to everyone on the winning team
1049 for (itPlayers = game->getPlayers().begin(); itPlayers != game->getPlayers().end(); itPlayers++) {
1050 if (itPlayers->second->team == p->team) {
1051 itPlayers->second->honor += 150;
1052 da->updatePlayer(itPlayers->second);
1053 }
1054 }
1055 }
1056
1057 // this means a PLAYER message will be sent
1058 broadcastMove = true;
1059 }
1060
1061 // go through all objects and check if the player is close to one and if its their flag
1062 vector<WorldMap::Object>* vctObjects = game->getMap()->getObjects();
1063 vector<WorldMap::Object>::iterator itObjects;
1064 POSITION structPos;
1065
1066 for (itObjects = vctObjects->begin(); itObjects != vctObjects->end(); itObjects++) {
1067 POSITION pos = itObjects->pos;
1068
1069 if (posDistance(p->pos, pos.toFloat()) < 10) {
1070 if (p->team == Player::TEAM_BLUE && itObjects->type == OBJECT_BLUE_FLAG) {
1071 structPos = game->getMap()->getStructureLocation(STRUCTURE_BLUE_FLAG);
1072 flagReturned = true;
1073 break;
1074 } else if (p->team == Player::TEAM_RED && itObjects->type == OBJECT_RED_FLAG) {
1075 structPos = game->getMap()->getStructureLocation(STRUCTURE_RED_FLAG);
1076 flagReturned = true;
1077 break;
1078 }
1079 }
1080 }
1081
1082 if (flagReturned) {
1083 itObjects->pos.x = structPos.x*25+12;
1084 itObjects->pos.y = structPos.y*25+12;
1085
1086 serverMsg.type = MSG_TYPE_OBJECT;
1087 itObjects->serialize(serverMsg.buffer);
1088 msgProcessor->broadcastMessage(serverMsg, game->getPlayers());
1089 }
1090
1091 if (broadcastMove) {
1092 serverMsg.type = MSG_TYPE_PLAYER;
1093 p->serialize(serverMsg.buffer);
1094 msgProcessor->broadcastMessage(serverMsg, game->getPlayers());
1095 }
1096 }
1097
1098 cout << "processing player attack" << endl;
1099
1100 // check if the player's attack animation is complete
1101 if (p->isAttacking && p->timeAttackStarted+p->attackCooldown <= getCurrentMillis()) {
1102 p->isAttacking = false;
1103 cout << "Attack animation is complete" << endl;
1104
1105 //send everyone an ATTACK message
1106 cout << "about to broadcast attack" << endl;
1107
1108 if (p->attackType == Player::ATTACK_MELEE) {
1109 cout << "Melee attack" << endl;
1110
1111 Player* target = game->getPlayers()[p->getTargetPlayer()];
1112 game->dealDamageToPlayer(target, p->damage);
1113 } else if (p->attackType == Player::ATTACK_RANGED) {
1114 cout << "Ranged attack" << endl;
1115
1116 Projectile proj(p->pos.x, p->pos.y, p->getTargetPlayer(), p->damage);
1117 game->assignProjectileId(&proj);
1118 game->addProjectile(proj);
1119
1120 int x = p->pos.x;
1121 int y = p->pos.y;
1122 unsigned int targetId = p->getTargetPlayer();
1123
1124 serverMsg.type = MSG_TYPE_PROJECTILE;
1125 memcpy(serverMsg.buffer, &proj.id, 4);
1126 memcpy(serverMsg.buffer+4, &x, 4);
1127 memcpy(serverMsg.buffer+8, &y, 4);
1128 memcpy(serverMsg.buffer+12, &targetId, 4);
1129 msgProcessor->broadcastMessage(serverMsg, game->getPlayers());
1130 } else
1131 cout << "Invalid attack type: " << p->attackType << endl;
1132 }
1133
1134 return gameFinished;
1135}
1136
1137void quit(int sig) {
1138 done = true;
1139}
Note: See TracBrowser for help on using the repository browser.