source: network-game/server/server.cpp@ d3e8f60

Last change on this file since d3e8f60 was 5b1e31e, checked in by dportnoy <dmp1488@…>, 12 years ago

Fix some bugs related to player attack and movement

  • Property mode set to 100644
File size: 30.2 KB
Line 
1#include <cstdlib>
2#include <cstdio>
3#include <unistd.h>
4#include <string>
5#include <iostream>
6#include <sstream>
7#include <cstring>
8#include <cmath>
9
10#include <vector>
11#include <map>
12
13#include <sys/time.h>
14
15#include <sys/socket.h>
16#include <netdb.h>
17#include <netinet/in.h>
18#include <arpa/inet.h>
19
20#include <crypt.h>
21
22/*
23#include <openssl/bio.h>
24#include <openssl/ssl.h>
25#include <openssl/err.h>
26*/
27
28#include "../common/Compiler.h"
29#include "../common/Common.h"
30#include "../common/Message.h"
31#include "../common/WorldMap.h"
32#include "../common/Player.h"
33#include "../common/Projectile.h"
34
35#include "DataAccess.h"
36
37using namespace std;
38
39// from used to be const. Removed that so I could take a reference
40// and use it to send messages
41bool processMessage(const NETWORK_MSG &clientMsg, struct sockaddr_in &from, map<unsigned int, Player>& mapPlayers, WorldMap* gameMap, unsigned int& unusedPlayerId, NETWORK_MSG &serverMsg, int sock, int &scoreBlue, int &scoreRed);
42
43void updateUnusedPlayerId(unsigned int& id, map<unsigned int, Player>& mapPlayers);
44void updateUnusedProjectileId(unsigned int& id, map<unsigned int, Projectile>& mapProjectiles);
45
46// this should probably go somewhere in the common folder
47void error(const char *msg)
48{
49 perror(msg);
50 exit(0);
51}
52
53Player *findPlayerByName(map<unsigned int, Player> &m, string name)
54{
55 map<unsigned int, Player>::iterator it;
56
57 for (it = m.begin(); it != m.end(); it++)
58 {
59 if ( it->second.name.compare(name) == 0 )
60 return &(it->second);
61 }
62
63 return NULL;
64}
65
66Player *findPlayerByAddr(map<unsigned int, Player> &m, const sockaddr_in &addr)
67{
68 map<unsigned int, Player>::iterator it;
69
70 for (it = m.begin(); it != m.end(); it++)
71 {
72 if ( it->second.addr.sin_addr.s_addr == addr.sin_addr.s_addr &&
73 it->second.addr.sin_port == addr.sin_port )
74 return &(it->second);
75 }
76
77 return NULL;
78}
79
80int main(int argc, char *argv[])
81{
82 int sock, length, n;
83 struct sockaddr_in server;
84 struct sockaddr_in from; // info of client sending the message
85 NETWORK_MSG clientMsg, serverMsg;
86 map<unsigned int, Player> mapPlayers;
87 map<unsigned int, Projectile> mapProjectiles;
88 unsigned int unusedPlayerId = 1, unusedProjectileId = 1;
89 int scoreBlue, scoreRed;
90
91 scoreBlue = 0;
92 scoreRed = 0;
93
94 //SSL_load_error_strings();
95 //ERR_load_BIO_strings();
96 //OpenSSL_add_all_algorithms();
97
98 if (argc < 2) {
99 cerr << "ERROR, no port provided" << endl;
100 exit(1);
101 }
102
103 WorldMap* gameMap = WorldMap::loadMapFromFile("../data/map.txt");
104
105 // add some items to the map. They will be sent out
106 // to players when they login
107 for (int y=0; y<gameMap->height; y++) {
108 for (int x=0; x<gameMap->width; x++) {
109 switch (gameMap->getStructure(x, y)) {
110 case WorldMap::STRUCTURE_BLUE_FLAG:
111 gameMap->addObject(WorldMap::OBJECT_BLUE_FLAG, x*25+12, y*25+12);
112 break;
113 case WorldMap::STRUCTURE_RED_FLAG:
114 gameMap->addObject(WorldMap::OBJECT_RED_FLAG, x*25+12, y*25+12);
115 break;
116 }
117 }
118 }
119
120 sock = socket(AF_INET, SOCK_DGRAM, 0);
121 if (sock < 0)
122 error("Opening socket");
123 length = sizeof(server);
124 bzero(&server,length);
125 server.sin_family=AF_INET;
126 server.sin_port=htons(atoi(argv[1]));
127 server.sin_addr.s_addr=INADDR_ANY;
128 if ( bind(sock, (struct sockaddr *)&server, length) < 0 )
129 error("binding");
130
131 set_nonblock(sock);
132
133 bool broadcastResponse;
134 timespec ts;
135 int timeLastUpdated = 0, curTime = 0, timeLastBroadcast = 0;
136 while (true) {
137
138 usleep(5000);
139
140 clock_gettime(CLOCK_REALTIME, &ts);
141 // make the number smaller so millis can fit in an int
142 ts.tv_sec -= 1368000000;
143 curTime = ts.tv_sec*1000 + ts.tv_nsec/1000000;
144
145 if (timeLastUpdated == 0 || (curTime-timeLastUpdated) >= 50) {
146 timeLastUpdated = curTime;
147
148 map<unsigned int, Player>::iterator it;
149
150 // set targets for all chasing players (or make them attack if they're close enough)
151 for (it = mapPlayers.begin(); it != mapPlayers.end(); it++) {
152 if (it->second.updateTarget(mapPlayers)) {
153 serverMsg.type = MSG_TYPE_PLAYER;
154 it->second.serialize(serverMsg.buffer);
155
156 map<unsigned int, Player>::iterator it2;
157 for (it2 = mapPlayers.begin(); it2 != mapPlayers.end(); it2++)
158 {
159 if ( sendMessage(&serverMsg, sock, &(it2->second.addr)) < 0 )
160 error("sendMessage");
161 }
162 }
163 }
164
165 // move all players
166 // maybe put this in a separate method
167 FLOAT_POSITION oldPos;
168 bool broadcastMove = false;
169 for (it = mapPlayers.begin(); it != mapPlayers.end(); it++) {
170 cout << "Starting new for loop iteration" << endl;
171 oldPos = it->second.pos;
172 if (it->second.move(gameMap)) {
173
174 // check if the move needs to be canceled
175 switch(gameMap->getElement(it->second.pos.x/25, it->second.pos.y/25)) {
176 case WorldMap::TERRAIN_NONE:
177 case WorldMap::TERRAIN_OCEAN:
178 case WorldMap::TERRAIN_ROCK:
179 {
180 it->second.pos = oldPos;
181 it->second.target.x = it->second.pos.x;
182 it->second.target.y = it->second.pos.y;
183 it->second.isChasing = false;
184 broadcastMove = true;
185 break;
186 }
187 default:
188 // if there are no obstacles, do nothing
189 break;
190 }
191
192 WorldMap::ObjectType flagType;
193 POSITION pos;
194 bool flagTurnedIn = false;
195 bool flagReturned = false;
196 bool ownFlagAtBase = false;
197
198 switch(gameMap->getStructure(it->second.pos.x/25, it->second.pos.y/25)) {
199 case WorldMap::STRUCTURE_BLUE_FLAG:
200 {
201 if (it->second.team == 0 && it->second.hasRedFlag)
202 {
203 // check that your flag is at your base
204 pos = gameMap->getStructureLocation(WorldMap::STRUCTURE_BLUE_FLAG);
205
206 vector<WorldMap::Object>* vctObjects = gameMap->getObjects();
207 vector<WorldMap::Object>::iterator itObjects;
208
209 for (itObjects = vctObjects->begin(); itObjects != vctObjects->end(); itObjects++) {
210 if (itObjects->type == WorldMap::OBJECT_BLUE_FLAG) {
211 if (itObjects->pos.x == pos.x*25+12 && itObjects->pos.y == pos.y*25+12) {
212 ownFlagAtBase = true;
213 break;
214 }
215 }
216 }
217
218 if (ownFlagAtBase) {
219 it->second.hasRedFlag = false;
220 flagType = WorldMap::OBJECT_RED_FLAG;
221 pos = gameMap->getStructureLocation(WorldMap::STRUCTURE_RED_FLAG);
222 flagTurnedIn = true;
223 scoreBlue++;
224 }
225 }
226
227 break;
228 }
229 case WorldMap::STRUCTURE_RED_FLAG:
230 {
231 if (it->second.team == 1 && it->second.hasBlueFlag)
232 {
233 // check that your flag is at your base
234 pos = gameMap->getStructureLocation(WorldMap::STRUCTURE_RED_FLAG);
235
236 vector<WorldMap::Object>* vctObjects = gameMap->getObjects();
237 vector<WorldMap::Object>::iterator itObjects;
238
239 for (itObjects = vctObjects->begin(); itObjects != vctObjects->end(); itObjects++) {
240 if (itObjects->type == WorldMap::OBJECT_RED_FLAG) {
241 if (itObjects->pos.x == pos.x*25+12 && itObjects->pos.y == pos.y*25+12) {
242 ownFlagAtBase = true;
243 break;
244 }
245 }
246 }
247
248 if (ownFlagAtBase) {
249 it->second.hasBlueFlag = false;
250 flagType = WorldMap::OBJECT_BLUE_FLAG;
251 pos = gameMap->getStructureLocation(WorldMap::STRUCTURE_BLUE_FLAG);
252 flagTurnedIn = true;
253 scoreRed++;
254 }
255 }
256
257 break;
258 }
259 }
260
261 if (flagTurnedIn) {
262 // send an OBJECT message to add the flag back to its spawn point
263 pos.x = pos.x*25+12;
264 pos.y = pos.y*25+12;
265 gameMap->addObject(flagType, pos.x, pos.y);
266
267 serverMsg.type = MSG_TYPE_OBJECT;
268 gameMap->getObjects()->back().serialize(serverMsg.buffer);
269
270 map<unsigned int, Player>::iterator it2;
271 for (it2 = mapPlayers.begin(); it2 != mapPlayers.end(); it2++)
272 {
273 if ( sendMessage(&serverMsg, sock, &(it2->second.addr)) < 0 )
274 error("sendMessage");
275 }
276
277 serverMsg.type = MSG_TYPE_SCORE;
278 memcpy(serverMsg.buffer, &scoreBlue, 4);
279 memcpy(serverMsg.buffer+4, &scoreRed, 4);
280
281 for (it2 = mapPlayers.begin(); it2 != mapPlayers.end(); it2++)
282 {
283 if ( sendMessage(&serverMsg, sock, &(it2->second.addr)) < 0 )
284 error("sendMessage");
285 }
286
287 // this means a PLAYER message will be sent
288 broadcastMove = true;
289 }
290
291 // go through all objects and check if the player is close to one and if its their flag
292 vector<WorldMap::Object>* vctObjects = gameMap->getObjects();
293 vector<WorldMap::Object>::iterator itObjects;
294 POSITION structPos;
295
296 for (itObjects = vctObjects->begin(); itObjects != vctObjects->end(); itObjects++) {
297 POSITION pos = itObjects->pos;
298
299 if (posDistance(it->second.pos, pos.toFloat()) < 10) {
300 if (it->second.team == 0 &&
301 itObjects->type == WorldMap::OBJECT_BLUE_FLAG) {
302 structPos = gameMap->getStructureLocation(WorldMap::STRUCTURE_BLUE_FLAG);
303 flagReturned = true;
304 break;
305 } else if (it->second.team == 1 &&
306 itObjects->type == WorldMap::OBJECT_RED_FLAG) {
307 structPos = gameMap->getStructureLocation(WorldMap::STRUCTURE_RED_FLAG);
308 flagReturned = true;
309 break;
310 }
311 }
312 }
313
314 if (flagReturned) {
315 itObjects->pos.x = structPos.x*25+12;
316 itObjects->pos.y = structPos.y*25+12;
317
318 serverMsg.type = MSG_TYPE_OBJECT;
319 itObjects->serialize(serverMsg.buffer);
320
321 map<unsigned int, Player>::iterator it2;
322 for (it2 = mapPlayers.begin(); it2 != mapPlayers.end(); it2++)
323 {
324 if ( sendMessage(&serverMsg, sock, &(it2->second.addr)) < 0 )
325 error("sendMessage");
326 }
327 }
328
329 if (broadcastMove) {
330 serverMsg.type = MSG_TYPE_PLAYER;
331 it->second.serialize(serverMsg.buffer);
332
333 cout << "about to broadcast move" << endl;
334 map<unsigned int, Player>::iterator it2;
335 for (it2 = mapPlayers.begin(); it2 != mapPlayers.end(); it2++)
336 {
337 if ( sendMessage(&serverMsg, sock, &(it2->second.addr)) < 0 )
338 error("sendMessage");
339 }
340 }
341 }
342
343 // check if the player's attack animation is complete
344 if (it->second.isAttacking && it->second.timeAttackStarted+it->second.attackCooldown <= getCurrentMillis()) {
345 it->second.isAttacking = false;
346 cout << "Attack animation is complete" << endl;
347
348 //send everyone an ATTACK message
349 cout << "about to broadcast attack" << endl;
350
351 serverMsg.type = MSG_TYPE_ATTACK;
352 memcpy(serverMsg.buffer, &it->second.id, 4);
353 memcpy(serverMsg.buffer+4, &it->second.targetPlayer, 4);
354
355 map<unsigned int, Player>::iterator it2;
356 for (it2 = mapPlayers.begin(); it2 != mapPlayers.end(); it2++)
357 {
358 if ( sendMessage(&serverMsg, sock, &(it2->second.addr)) < 0 )
359 error("sendMessage");
360 }
361
362 if (it->second.attackType == Player::ATTACK_MELEE) {
363 cout << "Melee attack" << endl;
364
365 Player* target = &mapPlayers[it->second.targetPlayer];
366
367 target->health -= it->second.damage;
368 if (target->health < 0)
369 target->health = 0;
370
371 serverMsg.type = MSG_TYPE_PLAYER;
372 target->serialize(serverMsg.buffer);
373 }else if (it->second.attackType == Player::ATTACK_RANGED) {
374 cout << "Ranged attack" << endl;
375
376 Projectile proj(it->second.pos.x, it->second.pos.y, it->second.targetPlayer, it->second.damage);
377 proj.id = unusedProjectileId;
378 updateUnusedProjectileId(unusedProjectileId, mapProjectiles);
379 mapProjectiles[proj.id] = proj;
380
381 int x = it->second.pos.x;
382 int y = it->second.pos.y;
383
384 serverMsg.type = MSG_TYPE_PROJECTILE;
385 memcpy(serverMsg.buffer, &proj.id, 4);
386 memcpy(serverMsg.buffer+4, &x, 4);
387 memcpy(serverMsg.buffer+8, &y, 4);
388 memcpy(serverMsg.buffer+12, &it->second.targetPlayer, 4);
389 }else {
390 cout << "Invalid attack type: " << it->second.attackType << endl;
391 }
392
393 // broadcast either a PLAYER or PROJECTILE message
394 cout << "Broadcasting player or projectile message" << endl;
395 for (it2 = mapPlayers.begin(); it2 != mapPlayers.end(); it2++)
396 {
397 if (sendMessage(&serverMsg, sock, &(it2->second.addr)) < 0 )
398 error("sendMessage");
399 }
400 cout << "Done broadcasting" << endl;
401 }
402 }
403
404 cout << "Done with the for loop" << endl;
405
406 // move all projectiles
407 cout << "Moving projectiles" << endl;
408 map<unsigned int, Projectile>::iterator itProj;
409 for (itProj = mapProjectiles.begin(); itProj != mapProjectiles.end(); itProj++) {
410 if (itProj->second.move(mapPlayers)) {
411 // send a REMOVE_PROJECTILE message
412 cout << "send a REMOVE_PROJECTILE message" << endl;
413 serverMsg.type = MSG_TYPE_REMOVE_PROJECTILE;
414 memcpy(serverMsg.buffer, &itProj->second.id, 4);
415 mapProjectiles.erase(itProj->second.id);
416
417 map<unsigned int, Player>::iterator it2;
418 cout << "Broadcasting REMOVE_PROJECTILE" << endl;
419 for (it2 = mapPlayers.begin(); it2 != mapPlayers.end(); it2++)
420 {
421 if ( sendMessage(&serverMsg, sock, &(it2->second.addr)) < 0 )
422 error("sendMessage");
423 }
424
425 cout << "send a PLAYER message after dealing damage" << endl;
426 // send a PLAYER message after dealing damage
427 Player* target = &mapPlayers[itProj->second.target];
428
429 target->health -= itProj->second.damage;
430 if (target->health < 0)
431 target->health = 0;
432
433 serverMsg.type = MSG_TYPE_PLAYER;
434 target->serialize(serverMsg.buffer);
435
436 cout << "Sending a PLAYER message" << endl;
437 for (it2 = mapPlayers.begin(); it2 != mapPlayers.end(); it2++)
438 {
439 if ( sendMessage(&serverMsg, sock, &(it2->second.addr)) < 0 )
440 error("sendMessage");
441 }
442 }
443 }
444 }
445 cout << "Done moving projectiles" << endl;
446
447 n = receiveMessage(&clientMsg, sock, &from);
448
449 if (n >= 0) {
450 broadcastResponse = processMessage(clientMsg, from, mapPlayers, gameMap, unusedPlayerId, serverMsg, sock, scoreBlue, scoreRed);
451
452 if (broadcastResponse)
453 {
454 cout << "Should be broadcasting the message" << endl;
455
456 map<unsigned int, Player>::iterator it;
457 for (it = mapPlayers.begin(); it != mapPlayers.end(); it++)
458 {
459 cout << "Sent message back to " << it->second.name << endl;
460 if ( sendMessage(&serverMsg, sock, &(it->second.addr)) < 0 )
461 error("sendMessage");
462 }
463 }
464 else
465 {
466 cout << "Should be sending back the message" << endl;
467
468 if ( sendMessage(&serverMsg, sock, &from) < 0 )
469 error("sendMessage");
470 }
471 }
472 }
473
474 return 0;
475}
476
477bool processMessage(const NETWORK_MSG& clientMsg, struct sockaddr_in& from, map<unsigned int, Player>& mapPlayers, WorldMap* gameMap, unsigned int& unusedPlayerId, NETWORK_MSG& serverMsg, int sock, int &scoreBlue, int &scoreRed)
478{
479 DataAccess da;
480
481 cout << "Received message" << endl;
482 cout << "MSG: type: " << clientMsg.type << endl;
483 cout << "MSG contents: " << clientMsg.buffer << endl;
484
485 // maybe we should make a message class and have this be a member
486 bool broadcastResponse = false;
487
488 // Check that if an invalid message is sent, the client will correctly
489 // receive and display the response. Maybe make a special error msg type
490 switch(clientMsg.type)
491 {
492 case MSG_TYPE_REGISTER:
493 {
494 string username(clientMsg.buffer);
495 string password(strchr(clientMsg.buffer, '\0')+1);
496
497 cout << "username: " << username << endl;
498 cout << "password: " << password << endl;
499
500 int error = da.insertPlayer(username, password);
501
502 if (!error)
503 strcpy(serverMsg.buffer, "Registration successful.");
504 else
505 strcpy(serverMsg.buffer, "Registration failed. Please try again.");
506
507 serverMsg.type = MSG_TYPE_REGISTER;
508
509 break;
510 }
511 case MSG_TYPE_LOGIN:
512 {
513 cout << "Got login message" << endl;
514
515 serverMsg.type = MSG_TYPE_LOGIN;
516
517 string username(clientMsg.buffer);
518 string password(strchr(clientMsg.buffer, '\0')+1);
519
520 Player* p = da.getPlayer(username);
521
522 if (p == NULL || !da.verifyPassword(password, p->password))
523 {
524 strcpy(serverMsg.buffer, "Incorrect username or password");
525 }
526 else if(findPlayerByName(mapPlayers, username) != NULL)
527 {
528 strcpy(serverMsg.buffer, "Player has already logged in.");
529 }
530 else
531 {
532 serverMsg.type = MSG_TYPE_PLAYER;
533
534 updateUnusedPlayerId(unusedPlayerId, mapPlayers);
535 p->id = unusedPlayerId;
536 cout << "new player id: " << p->id << endl;
537 p->setAddr(from);
538
539 // choose a random team (either 0 or 1)
540 p->team = rand() % 2;
541
542 // choose a random class
543 int intClass = rand() % 2;
544 switch (intClass) {
545 case 0:
546 p->setClass(Player::CLASS_WARRIOR);
547 break;
548 case 1:
549 p->setClass(Player::CLASS_RANGER);
550 break;
551 }
552
553 // tell the new player about all the existing players
554 cout << "Sending other players to new player" << endl;
555
556 map<unsigned int, Player>::iterator it;
557 for (it = mapPlayers.begin(); it != mapPlayers.end(); it++)
558 {
559 it->second.serialize(serverMsg.buffer);
560
561 cout << "sending info about " << it->second.name << endl;
562 cout << "sending id " << it->second.id << endl;
563 if ( sendMessage(&serverMsg, sock, &from) < 0 )
564 error("sendMessage");
565 }
566
567 // tell the new player about all map objects
568 // (currently just the flags)
569 serverMsg.type = MSG_TYPE_OBJECT;
570 vector<WorldMap::Object>* vctObjects = gameMap->getObjects();
571 vector<WorldMap::Object>::iterator itObjects;
572 cout << "sending items" << endl;
573 for (itObjects = vctObjects->begin(); itObjects != vctObjects->end(); itObjects++) {
574 itObjects->serialize(serverMsg.buffer);
575 cout << "sending item id " << itObjects->id << endl;
576 if ( sendMessage(&serverMsg, sock, &from) < 0 )
577 error("sendMessage");
578 }
579
580 // send the current score
581 serverMsg.type = MSG_TYPE_SCORE;
582 memcpy(serverMsg.buffer, &scoreBlue, 4);
583 memcpy(serverMsg.buffer+4, &scoreRed, 4);
584 if ( sendMessage(&serverMsg, sock, &from) < 0 )
585 error("sendMessage");
586
587 serverMsg.type = MSG_TYPE_PLAYER;
588 p->serialize(serverMsg.buffer);
589 cout << "Should be broadcasting the message" << endl;
590
591 for (it = mapPlayers.begin(); it != mapPlayers.end(); it++)
592 {
593 cout << "Sent message back to " << it->second.name << endl;
594 if ( sendMessage(&serverMsg, sock, &(it->second.addr)) < 0 )
595 error("sendMessage");
596 }
597
598 serverMsg.type = MSG_TYPE_LOGIN;
599 mapPlayers[unusedPlayerId] = *p;
600 }
601
602 delete(p);
603
604 break;
605 }
606 case MSG_TYPE_LOGOUT:
607 {
608 string name(clientMsg.buffer);
609 cout << "Player logging out: " << name << endl;
610
611 Player *p = findPlayerByName(mapPlayers, name);
612
613 if (p == NULL)
614 {
615 strcpy(serverMsg.buffer, "That player is not logged in. This is either a bug, or you're trying to hack the server.");
616 cout << "Player not logged in" << endl;
617 }
618 else if ( p->addr.sin_addr.s_addr != from.sin_addr.s_addr ||
619 p->addr.sin_port != from.sin_port )
620 {
621 strcpy(serverMsg.buffer, "That player is logged in using a differemt connection. This is either a bug, or you're trying to hack the server.");
622 cout << "Player logged in using a different connection" << endl;
623 }
624 else
625 {
626 if (p->id < unusedPlayerId)
627 unusedPlayerId = p->id;
628 mapPlayers.erase(p->id);
629 strcpy(serverMsg.buffer, "You have successfully logged out.");
630 }
631
632 serverMsg.type = MSG_TYPE_LOGOUT;
633
634 break;
635 }
636 case MSG_TYPE_CHAT:
637 {
638 cout << "Got a chat message" << endl;
639
640 Player *p = findPlayerByAddr(mapPlayers, from);
641
642 if (p == NULL)
643 {
644 strcpy(serverMsg.buffer, "No player is logged in using this connection. This is either a bug, or you're trying to hack the server.");
645 }
646 else
647 {
648 broadcastResponse = true;
649
650 ostringstream oss;
651 oss << p->name << ": " << clientMsg.buffer;
652
653 strcpy(serverMsg.buffer, oss.str().c_str());
654 }
655
656 serverMsg.type = MSG_TYPE_CHAT;
657
658 break;
659 }
660 case MSG_TYPE_PLAYER_MOVE:
661 {
662 cout << "PLAYER_MOVE" << endl;
663
664 int id, x, y;
665
666 memcpy(&id, clientMsg.buffer, 4);
667 memcpy(&x, clientMsg.buffer+4, 4);
668 memcpy(&y, clientMsg.buffer+8, 4);
669
670 cout << "x: " << x << endl;
671 cout << "y: " << y << endl;
672 cout << "id: " << id << endl;
673
674 if ( mapPlayers[id].addr.sin_addr.s_addr == from.sin_addr.s_addr &&
675 mapPlayers[id].addr.sin_port == from.sin_port )
676 {
677 // we need to make sure the player can move here
678 if (0 <= x && x < 300 && 0 <= y && y < 300 &&
679 gameMap->getElement(x/25, y/25) == WorldMap::TERRAIN_GRASS)
680 {
681 cout << "valid terrain" << endl;
682
683 mapPlayers[id].target.x = x;
684 mapPlayers[id].target.y = y;
685
686 mapPlayers[id].isChasing = false;
687 mapPlayers[id].isAttacking = false;
688
689 serverMsg.type = MSG_TYPE_PLAYER_MOVE;
690
691 memcpy(serverMsg.buffer, &id, 4);
692 memcpy(serverMsg.buffer+4, &mapPlayers[id].target.x, 4);
693 memcpy(serverMsg.buffer+8, &mapPlayers[id].target.y, 4);
694
695 broadcastResponse = true;
696 }
697 else
698 cout << "Bad terrain detected" << endl;
699 }
700 else // nned to send back a message indicating failure
701 cout << "Player id (" << id << ") doesn't match sender" << endl;
702
703 break;
704 }
705 case MSG_TYPE_PICKUP_FLAG:
706 {
707 // may want to check the id matches the sender, just like for PLAYER_NOVE
708 cout << "PICKUP_FLAG" << endl;
709
710 int id;
711
712 memcpy(&id, clientMsg.buffer, 4);
713 cout << "id: " << id << endl;
714
715 vector<WorldMap::Object>* vctObjects = gameMap->getObjects();
716 vector<WorldMap::Object>::iterator itObjects;
717
718 for (itObjects = vctObjects->begin(); itObjects != vctObjects->end();) {
719 POSITION pos = itObjects->pos;
720 bool gotFlag = false;
721
722 if (posDistance(mapPlayers[id].pos, pos.toFloat()) < 10) {
723 switch (itObjects->type) {
724 case WorldMap::OBJECT_BLUE_FLAG:
725 if (mapPlayers[id].team == 1) {
726 gotFlag = true;
727 mapPlayers[id].hasBlueFlag = true;
728 broadcastResponse = true;
729 }
730 break;
731 case WorldMap::OBJECT_RED_FLAG:
732 if (mapPlayers[id].team == 0) {
733 gotFlag = true;
734 mapPlayers[id].hasRedFlag = true;
735 broadcastResponse = true;
736 }
737 break;
738 }
739
740 if (gotFlag) {
741 serverMsg.type = MSG_TYPE_REMOVE_OBJECT;
742 memcpy(serverMsg.buffer, &itObjects->id, 4);
743
744 map<unsigned int, Player>::iterator it;
745 for (it = mapPlayers.begin(); it != mapPlayers.end(); it++)
746 {
747 if ( sendMessage(&serverMsg, sock, &(it->second.addr)) < 0 )
748 error("sendMessage");
749 }
750
751 // remove the object from the server-side map
752 cout << "size before: " << gameMap->getObjects()->size() << endl;
753 itObjects = vctObjects->erase(itObjects);
754 cout << "size after: " << gameMap->getObjects()->size() << endl;
755 }
756 }
757
758 if (!gotFlag)
759 itObjects++;
760 }
761
762 serverMsg.type = MSG_TYPE_PLAYER;
763 mapPlayers[id].serialize(serverMsg.buffer);
764
765 break;
766 }
767 case MSG_TYPE_DROP_FLAG:
768 {
769 // may want to check the id matches the sender, just like for PLAYER_NOVE
770 cout << "DROP_FLAG" << endl;
771
772 int id;
773
774 memcpy(&id, clientMsg.buffer, 4);
775 cout << "id: " << id << endl;
776
777 WorldMap::ObjectType flagType = WorldMap::OBJECT_NONE;
778 if (mapPlayers[id].hasBlueFlag)
779 flagType = WorldMap::OBJECT_BLUE_FLAG;
780 else if (mapPlayers[id].hasRedFlag)
781 flagType = WorldMap::OBJECT_RED_FLAG;
782
783 gameMap->addObject(flagType, mapPlayers[id].pos.x, mapPlayers[id].pos.y);
784
785 // need to send the OBJECT message too
786 serverMsg.type = MSG_TYPE_OBJECT;
787 gameMap->getObjects()->back().serialize(serverMsg.buffer);
788
789 map<unsigned int, Player>::iterator it;
790 for (it = mapPlayers.begin(); it != mapPlayers.end(); it++)
791 {
792 if ( sendMessage(&serverMsg, sock, &(it->second.addr)) < 0 )
793 error("sendMessage");
794 }
795
796 mapPlayers[id].hasBlueFlag = false;
797 mapPlayers[id].hasRedFlag = false;
798
799 serverMsg.type = MSG_TYPE_PLAYER;
800 mapPlayers[id].serialize(serverMsg.buffer);
801
802 broadcastResponse = true;
803
804 break;
805 }
806 case MSG_TYPE_START_ATTACK:
807 {
808 cout << "Received a START_ATTACK message" << endl;
809
810 int id, targetId;
811
812 memcpy(&id, clientMsg.buffer, 4);
813 memcpy(&targetId, clientMsg.buffer+4, 4);
814
815 Player* source = &mapPlayers[id];
816 source->targetPlayer = targetId;
817 source->isChasing = true;
818
819 // this is irrelevant since the client doesn't even listen for START_ATTACK messages
820 // actually, the client should not ignore this and should instead perform the same movement
821 // algorithm on its end (following the target player until in range) that the server does.
822 // Once the attacker is in range, the client should stop movement and wait for messages
823 // from the server
824 serverMsg.type = MSG_TYPE_START_ATTACK;
825 memcpy(serverMsg.buffer, &id, 4);
826 memcpy(serverMsg.buffer+4, &targetId, 4);
827 broadcastResponse = true;
828
829 break;
830 }
831 case MSG_TYPE_ATTACK:
832 {
833 cout << "Received am ATTACK message" << endl;
834 cout << "ERROR: Clients should not send ATTACK messages" << endl;
835
836 break;
837 }
838 default:
839 {
840 strcpy(serverMsg.buffer, "Server error occured. Report this please.");
841
842 serverMsg.type = MSG_TYPE_CHAT;
843
844 break;
845 }
846 }
847
848 return broadcastResponse;
849}
850
851void updateUnusedPlayerId(unsigned int& id, map<unsigned int, Player>& mapPlayers)
852{
853 while (mapPlayers.find(id) != mapPlayers.end())
854 id++;
855}
856
857void updateUnusedProjectileId(unsigned int& id, map<unsigned int, Projectile>& mapProjectiles)
858{
859 while (mapProjectiles.find(id) != mapProjectiles.end())
860 id++;
861}
Note: See TracBrowser for help on using the repository browser.