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
RevLine 
[2488852]1#include <cstdlib>
[371ce29]2#include <cstdio>
[e3535b3]3#include <unistd.h>
[2488852]4#include <string>
[e3535b3]5#include <iostream>
[3b1efcc]6#include <sstream>
[edfd1d0]7#include <cstring>
[60017fc]8#include <cmath>
[371ce29]9
[01d0d00]10#include <vector>
11#include <map>
12
[d211210]13#include <sys/time.h>
14
[73f75c1]15#include <sys/socket.h>
[371ce29]16#include <netdb.h>
[73f75c1]17#include <netinet/in.h>
18#include <arpa/inet.h>
19
[b128109]20#include <crypt.h>
21
[edfd1d0]22/*
[e3535b3]23#include <openssl/bio.h>
24#include <openssl/ssl.h>
25#include <openssl/err.h>
[edfd1d0]26*/
[e3535b3]27
[b53c6b3]28#include "../common/Compiler.h"
[3b1efcc]29#include "../common/Common.h"
[edfd1d0]30#include "../common/Message.h"
[60017fc]31#include "../common/WorldMap.h"
[edfd1d0]32#include "../common/Player.h"
[8dad966]33#include "../common/Projectile.h"
[b53c6b3]34
[36082e8]35#include "DataAccess.h"
[d2b411a]36
[e3535b3]37using namespace std;
38
[d211210]39// from used to be const. Removed that so I could take a reference
40// and use it to send messages
[8dad966]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);
[01d0d00]42
[8dad966]43void updateUnusedPlayerId(unsigned int& id, map<unsigned int, Player>& mapPlayers);
44void updateUnusedProjectileId(unsigned int& id, map<unsigned int, Projectile>& mapProjectiles);
[8e540f4]45
[73f75c1]46// this should probably go somewhere in the common folder
[e3535b3]47void error(const char *msg)
48{
49 perror(msg);
50 exit(0);
51}
52
[01d0d00]53Player *findPlayerByName(map<unsigned int, Player> &m, string name)
[2488852]54{
[01d0d00]55 map<unsigned int, Player>::iterator it;
[2488852]56
[01d0d00]57 for (it = m.begin(); it != m.end(); it++)
[2488852]58 {
[01d0d00]59 if ( it->second.name.compare(name) == 0 )
60 return &(it->second);
[2488852]61 }
62
63 return NULL;
64}
65
[01d0d00]66Player *findPlayerByAddr(map<unsigned int, Player> &m, const sockaddr_in &addr)
[73f75c1]67{
[01d0d00]68 map<unsigned int, Player>::iterator it;
[73f75c1]69
[01d0d00]70 for (it = m.begin(); it != m.end(); it++)
[73f75c1]71 {
[01d0d00]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);
[73f75c1]75 }
76
77 return NULL;
78}
79
[e3535b3]80int main(int argc, char *argv[])
81{
82 int sock, length, n;
83 struct sockaddr_in server;
[3b1efcc]84 struct sockaddr_in from; // info of client sending the message
[e084950]85 NETWORK_MSG clientMsg, serverMsg;
[01d0d00]86 map<unsigned int, Player> mapPlayers;
[8dad966]87 map<unsigned int, Projectile> mapProjectiles;
88 unsigned int unusedPlayerId = 1, unusedProjectileId = 1;
[b8601ee]89 int scoreBlue, scoreRed;
90
91 scoreBlue = 0;
92 scoreRed = 0;
[e084950]93
[edfd1d0]94 //SSL_load_error_strings();
95 //ERR_load_BIO_strings();
96 //OpenSSL_add_all_algorithms();
[e3535b3]97
98 if (argc < 2) {
[73f75c1]99 cerr << "ERROR, no port provided" << endl;
100 exit(1);
[e3535b3]101 }
[60017fc]102
[7b43385]103 WorldMap* gameMap = WorldMap::loadMapFromFile("../data/map.txt");
[6e66ffd]104
105 // add some items to the map. They will be sent out
106 // to players when they login
[5f868c0]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 }
[6e66ffd]119
[371ce29]120 sock = socket(AF_INET, SOCK_DGRAM, 0);
[5b1e31e]121 if (sock < 0)
122 error("Opening socket");
[e3535b3]123 length = sizeof(server);
124 bzero(&server,length);
125 server.sin_family=AF_INET;
126 server.sin_port=htons(atoi(argv[1]));
[2488852]127 server.sin_addr.s_addr=INADDR_ANY;
128 if ( bind(sock, (struct sockaddr *)&server, length) < 0 )
[e084950]129 error("binding");
[73f75c1]130
[371ce29]131 set_nonblock(sock);
132
[da692b9]133 bool broadcastResponse;
[d211210]134 timespec ts;
[430c80e]135 int timeLastUpdated = 0, curTime = 0, timeLastBroadcast = 0;
[cb1f288]136 while (true) {
[371ce29]137
138 usleep(5000);
139
[d211210]140 clock_gettime(CLOCK_REALTIME, &ts);
[430c80e]141 // make the number smaller so millis can fit in an int
[d69eb32]142 ts.tv_sec -= 1368000000;
[430c80e]143 curTime = ts.tv_sec*1000 + ts.tv_nsec/1000000;
[d211210]144
[430c80e]145 if (timeLastUpdated == 0 || (curTime-timeLastUpdated) >= 50) {
[d211210]146 timeLastUpdated = curTime;
147
[11d21ee]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++) {
[5b1e31e]152 if (it->second.updateTarget(mapPlayers)) {
153 serverMsg.type = MSG_TYPE_PLAYER;
154 it->second.serialize(serverMsg.buffer);
[11d21ee]155
[5b1e31e]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");
[11d21ee]161 }
162 }
163 }
164
[8dad966]165 // move all players
[d211210]166 // maybe put this in a separate method
[23559e7]167 FLOAT_POSITION oldPos;
168 bool broadcastMove = false;
[d211210]169 for (it = mapPlayers.begin(); it != mapPlayers.end(); it++) {
[ff2133a]170 cout << "Starting new for loop iteration" << endl;
[23559e7]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:
[e4c60ba]179 {
[23559e7]180 it->second.pos = oldPos;
181 it->second.target.x = it->second.pos.x;
182 it->second.target.y = it->second.pos.y;
[5b1e31e]183 it->second.isChasing = false;
[23559e7]184 broadcastMove = true;
185 break;
[e4c60ba]186 }
[23559e7]187 default:
188 // if there are no obstacles, do nothing
189 break;
190 }
191
[e4c60ba]192 WorldMap::ObjectType flagType;
193 POSITION pos;
[7553db9]194 bool flagTurnedIn = false;
[446dc65]195 bool flagReturned = false;
196 bool ownFlagAtBase = false;
197
[e4c60ba]198 switch(gameMap->getStructure(it->second.pos.x/25, it->second.pos.y/25)) {
199 case WorldMap::STRUCTURE_BLUE_FLAG:
200 {
[7553db9]201 if (it->second.team == 0 && it->second.hasRedFlag)
202 {
[446dc65]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 }
[e4c60ba]225 }
[7553db9]226
227 break;
[e4c60ba]228 }
229 case WorldMap::STRUCTURE_RED_FLAG:
230 {
[7553db9]231 if (it->second.team == 1 && it->second.hasBlueFlag)
232 {
[446dc65]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 }
[e4c60ba]255 }
256
[7553db9]257 break;
258 }
259 }
[e4c60ba]260
[7553db9]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);
[e4c60ba]266
[7553db9]267 serverMsg.type = MSG_TYPE_OBJECT;
268 gameMap->getObjects()->back().serialize(serverMsg.buffer);
[e4c60ba]269
[7553db9]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");
[e4c60ba]275 }
[7553db9]276
[b8601ee]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
[7553db9]287 // this means a PLAYER message will be sent
288 broadcastMove = true;
[e4c60ba]289 }
290
[446dc65]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
[23559e7]329 if (broadcastMove) {
330 serverMsg.type = MSG_TYPE_PLAYER;
331 it->second.serialize(serverMsg.buffer);
332
333 cout << "about to broadcast move" << endl;
[b07eeac]334 map<unsigned int, Player>::iterator it2;
[23559e7]335 for (it2 = mapPlayers.begin(); it2 != mapPlayers.end(); it2++)
336 {
337 if ( sendMessage(&serverMsg, sock, &(it2->second.addr)) < 0 )
338 error("sendMessage");
339 }
[d211210]340 }
341 }
[8dad966]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;
[8795a38]346 cout << "Attack animation is complete" << endl;
[8dad966]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) {
[ff2133a]363 cout << "Melee attack" << endl;
364
[8dad966]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) {
[ff2133a]374 cout << "Ranged attack" << endl;
375
[8dad966]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
[8795a38]381 int x = it->second.pos.x;
382 int y = it->second.pos.y;
383
[8dad966]384 serverMsg.type = MSG_TYPE_PROJECTILE;
[8795a38]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);
[8dad966]389 }else {
390 cout << "Invalid attack type: " << it->second.attackType << endl;
391 }
392
393 // broadcast either a PLAYER or PROJECTILE message
[ff2133a]394 cout << "Broadcasting player or projectile message" << endl;
[8dad966]395 for (it2 = mapPlayers.begin(); it2 != mapPlayers.end(); it2++)
396 {
[ff2133a]397 if (sendMessage(&serverMsg, sock, &(it2->second.addr)) < 0 )
[8dad966]398 error("sendMessage");
399 }
[ff2133a]400 cout << "Done broadcasting" << endl;
[8dad966]401 }
402 }
403
[ff2133a]404 cout << "Done with the for loop" << endl;
405
[8dad966]406 // move all projectiles
[ff2133a]407 cout << "Moving projectiles" << endl;
[8dad966]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
[ff2133a]412 cout << "send a REMOVE_PROJECTILE message" << endl;
[8dad966]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;
[ff2133a]418 cout << "Broadcasting REMOVE_PROJECTILE" << endl;
[8dad966]419 for (it2 = mapPlayers.begin(); it2 != mapPlayers.end(); it2++)
420 {
421 if ( sendMessage(&serverMsg, sock, &(it2->second.addr)) < 0 )
422 error("sendMessage");
423 }
424
[ff2133a]425 cout << "send a PLAYER message after dealing damage" << endl;
[8dad966]426 // send a PLAYER message after dealing damage
[8795a38]427 Player* target = &mapPlayers[itProj->second.target];
[8dad966]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
[ff2133a]436 cout << "Sending a PLAYER message" << endl;
[8dad966]437 for (it2 = mapPlayers.begin(); it2 != mapPlayers.end(); it2++)
438 {
439 if ( sendMessage(&serverMsg, sock, &(it2->second.addr)) < 0 )
440 error("sendMessage");
441 }
442 }
[d211210]443 }
444 }
[ff2133a]445 cout << "Done moving projectiles" << endl;
[d211210]446
[e084950]447 n = receiveMessage(&clientMsg, sock, &from);
[8e540f4]448
[371ce29]449 if (n >= 0) {
[8dad966]450 broadcastResponse = processMessage(clientMsg, from, mapPlayers, gameMap, unusedPlayerId, serverMsg, sock, scoreBlue, scoreRed);
[371ce29]451
[da692b9]452 if (broadcastResponse)
[3b1efcc]453 {
[da692b9]454 cout << "Should be broadcasting the message" << endl;
455
[01d0d00]456 map<unsigned int, Player>::iterator it;
457 for (it = mapPlayers.begin(); it != mapPlayers.end(); it++)
[3b1efcc]458 {
[d211210]459 cout << "Sent message back to " << it->second.name << endl;
[01d0d00]460 if ( sendMessage(&serverMsg, sock, &(it->second.addr)) < 0 )
[3b1efcc]461 error("sendMessage");
462 }
463 }
464 else
465 {
[da692b9]466 cout << "Should be sending back the message" << endl;
467
[3b1efcc]468 if ( sendMessage(&serverMsg, sock, &from) < 0 )
469 error("sendMessage");
470 }
[7b43385]471 }
[8e540f4]472 }
[371ce29]473
[8e540f4]474 return 0;
475}
476
[8dad966]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)
[8e540f4]478{
[41ad8ed]479 DataAccess da;
480
[b8cb03f]481 cout << "Received message" << endl;
[8e540f4]482 cout << "MSG: type: " << clientMsg.type << endl;
483 cout << "MSG contents: " << clientMsg.buffer << endl;
484
[da692b9]485 // maybe we should make a message class and have this be a member
[3b1efcc]486 bool broadcastResponse = false;
487
[8e540f4]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:
[d2b411a]493 {
[8e540f4]494 string username(clientMsg.buffer);
495 string password(strchr(clientMsg.buffer, '\0')+1);
[d2b411a]496
[8e540f4]497 cout << "username: " << username << endl;
498 cout << "password: " << password << endl;
[d2b411a]499
[3b1efcc]500 int error = da.insertPlayer(username, password);
[41ad8ed]501
[3b1efcc]502 if (!error)
503 strcpy(serverMsg.buffer, "Registration successful.");
504 else
505 strcpy(serverMsg.buffer, "Registration failed. Please try again.");
[8e540f4]506
507 serverMsg.type = MSG_TYPE_REGISTER;
[d2b411a]508
[8e540f4]509 break;
510 }
511 case MSG_TYPE_LOGIN:
512 {
[60017fc]513 cout << "Got login message" << endl;
514
[d211210]515 serverMsg.type = MSG_TYPE_LOGIN;
516
[8e540f4]517 string username(clientMsg.buffer);
[41ad8ed]518 string password(strchr(clientMsg.buffer, '\0')+1);
[8e540f4]519
[41ad8ed]520 Player* p = da.getPlayer(username);
[d2b411a]521
[b128109]522 if (p == NULL || !da.verifyPassword(password, p->password))
[41ad8ed]523 {
524 strcpy(serverMsg.buffer, "Incorrect username or password");
525 }
[01d0d00]526 else if(findPlayerByName(mapPlayers, username) != NULL)
[41ad8ed]527 {
528 strcpy(serverMsg.buffer, "Player has already logged in.");
529 }
530 else
[8e540f4]531 {
[d211210]532 serverMsg.type = MSG_TYPE_PLAYER;
533
[8dad966]534 updateUnusedPlayerId(unusedPlayerId, mapPlayers);
535 p->id = unusedPlayerId;
[d211210]536 cout << "new player id: " << p->id << endl;
[df79cfd]537 p->setAddr(from);
538
539 // choose a random team (either 0 or 1)
540 p->team = rand() % 2;
[d211210]541
[46fa35a]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
[d211210]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;
[5f868c0]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;
[e487381]570 vector<WorldMap::Object>* vctObjects = gameMap->getObjects();
[5f868c0]571 vector<WorldMap::Object>::iterator itObjects;
572 cout << "sending items" << endl;
[e487381]573 for (itObjects = vctObjects->begin(); itObjects != vctObjects->end(); itObjects++) {
[5f868c0]574 itObjects->serialize(serverMsg.buffer);
575 cout << "sending item id " << itObjects->id << endl;
[d211210]576 if ( sendMessage(&serverMsg, sock, &from) < 0 )
577 error("sendMessage");
578 }
[59061f6]579
[b8601ee]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;
[594d2e9]588 p->serialize(serverMsg.buffer);
[d211210]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;
[8dad966]599 mapPlayers[unusedPlayerId] = *p;
[07028b9]600 }
601
[41ad8ed]602 delete(p);
[07028b9]603
[8e540f4]604 break;
605 }
606 case MSG_TYPE_LOGOUT:
607 {
608 string name(clientMsg.buffer);
609 cout << "Player logging out: " << name << endl;
610
[01d0d00]611 Player *p = findPlayerByName(mapPlayers, name);
[633f42a]612
[8e540f4]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.");
[8a3ef42]616 cout << "Player not logged in" << endl;
[07028b9]617 }
[01d0d00]618 else if ( p->addr.sin_addr.s_addr != from.sin_addr.s_addr ||
619 p->addr.sin_port != from.sin_port )
[07028b9]620 {
[8e540f4]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.");
[8a3ef42]622 cout << "Player logged in using a different connection" << endl;
[2488852]623 }
[8e540f4]624 else
[2488852]625 {
[8dad966]626 if (p->id < unusedPlayerId)
627 unusedPlayerId = p->id;
[01d0d00]628 mapPlayers.erase(p->id);
[41ad8ed]629 strcpy(serverMsg.buffer, "You have successfully logged out.");
[8e540f4]630 }
[07028b9]631
[d211210]632 serverMsg.type = MSG_TYPE_LOGOUT;
[8a3ef42]633
[8e540f4]634 break;
635 }
636 case MSG_TYPE_CHAT:
637 {
[da692b9]638 cout << "Got a chat message" << endl;
639
[01d0d00]640 Player *p = findPlayerByAddr(mapPlayers, from);
[07028b9]641
[8e540f4]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.");
[2488852]645 }
[8e540f4]646 else
647 {
[3b1efcc]648 broadcastResponse = true;
649
[b128109]650 ostringstream oss;
651 oss << p->name << ": " << clientMsg.buffer;
[3b1efcc]652
[b128109]653 strcpy(serverMsg.buffer, oss.str().c_str());
[8e540f4]654 }
655
656 serverMsg.type = MSG_TYPE_CHAT;
657
658 break;
[e084950]659 }
[b128109]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);
[7b43385]669
[b128109]670 cout << "x: " << x << endl;
671 cout << "y: " << y << endl;
672 cout << "id: " << id << endl;
[7b43385]673
[b128109]674 if ( mapPlayers[id].addr.sin_addr.s_addr == from.sin_addr.s_addr &&
675 mapPlayers[id].addr.sin_port == from.sin_port )
676 {
[60017fc]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 {
[7b43385]681 cout << "valid terrain" << endl;
682
[60017fc]683 mapPlayers[id].target.x = x;
684 mapPlayers[id].target.y = y;
685
[5b1e31e]686 mapPlayers[id].isChasing = false;
687 mapPlayers[id].isAttacking = false;
688
[60017fc]689 serverMsg.type = MSG_TYPE_PLAYER_MOVE;
690
691 memcpy(serverMsg.buffer, &id, 4);
[d211210]692 memcpy(serverMsg.buffer+4, &mapPlayers[id].target.x, 4);
693 memcpy(serverMsg.buffer+8, &mapPlayers[id].target.y, 4);
[60017fc]694
695 broadcastResponse = true;
696 }
697 else
698 cout << "Bad terrain detected" << endl;
[b128109]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 }
[5299436]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
[5c84d54]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
[5299436]765 break;
766 }
[e487381]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 }
[4b4b153]806 case MSG_TYPE_START_ATTACK:
807 {
808 cout << "Received a START_ATTACK message" << endl;
809
[8a4ed74]810 int id, targetId;
811
812 memcpy(&id, clientMsg.buffer, 4);
813 memcpy(&targetId, clientMsg.buffer+4, 4);
814
[8dad966]815 Player* source = &mapPlayers[id];
816 source->targetPlayer = targetId;
[11d21ee]817 source->isChasing = true;
[8dad966]818
[11d21ee]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
[4b4b153]824 serverMsg.type = MSG_TYPE_START_ATTACK;
[8dad966]825 memcpy(serverMsg.buffer, &id, 4);
826 memcpy(serverMsg.buffer+4, &targetId, 4);
[4b4b153]827 broadcastResponse = true;
[8a4ed74]828
829 break;
[4b4b153]830 }
831 case MSG_TYPE_ATTACK:
832 {
833 cout << "Received am ATTACK message" << endl;
[8dad966]834 cout << "ERROR: Clients should not send ATTACK messages" << endl;
[8a4ed74]835
836 break;
[4b4b153]837 }
[8e540f4]838 default:
839 {
840 strcpy(serverMsg.buffer, "Server error occured. Report this please.");
[e084950]841
[8e540f4]842 serverMsg.type = MSG_TYPE_CHAT;
[e084950]843
[8e540f4]844 break;
845 }
[e3535b3]846 }
[da692b9]847
848 return broadcastResponse;
[e3535b3]849}
[da692b9]850
[8dad966]851void updateUnusedPlayerId(unsigned int& id, map<unsigned int, Player>& mapPlayers)
[01d0d00]852{
[1106210]853 while (mapPlayers.find(id) != mapPlayers.end())
854 id++;
[01d0d00]855}
[8dad966]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.