handler.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. /*
  2. * File: handler.c
  3. * Author: Arthur Brandao
  4. *
  5. * Created on 23 novembre 2018
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <unistd.h>
  10. #include "error.h"
  11. #include "bomberstudent_server.h"
  12. #include "client.h"
  13. #include "player.h"
  14. #include "delay.h"
  15. #include "handler.h"
  16. /* --- Extern --- */
  17. extern Game game[MAXGAME];
  18. extern int nbGame;
  19. pthread_mutex_t gameMutex[MAXGAME];
  20. pthread_mutex_t playerMutex[MAXGAME * MAXPLAYER];
  21. /* --- Fonctions privées --- */
  22. /**
  23. * Cherche dans quel partie est un client
  24. * @param int L'id du client
  25. * @return int L'index de la partie
  26. */
  27. int search_client_game(int cliId) {
  28. int index = ERR;
  29. for (int i = 0; i < MAXGAME; i++) {
  30. pthread_mutex_lock(&gameMutex[i]);
  31. //Regarde si la game est active et avec des joueurs
  32. if (game[i].active && game[i].nbPlayer > 0) {
  33. //Parcours les joueurs
  34. for (int j = 0; j < MAXPLAYER; j++) {
  35. pthread_mutex_lock(&playerMutex[(i * MAXPLAYER) + j]);
  36. //Si le joueur est actif
  37. if (game[i].player[j]->ini) {
  38. //Si l'id est le bon
  39. if (game[i].player[j]->id == cliId) {
  40. index = i;
  41. pthread_mutex_unlock(&playerMutex[(i * MAXPLAYER) + j]);
  42. break;
  43. }
  44. }
  45. pthread_mutex_unlock(&playerMutex[(i * MAXPLAYER) + j]);
  46. }
  47. }
  48. pthread_mutex_unlock(&gameMutex[i]);
  49. //Si on a un resultat
  50. if (index != ERR) {
  51. break;
  52. }
  53. }
  54. //Retour
  55. return index;
  56. }
  57. /**
  58. * Cherche une partie par son nom
  59. * @param char* Le nom de la partie
  60. * @return int L'index dans le tableau
  61. */
  62. int search_game(char* name) {
  63. int index = ERR;
  64. for (int i = 0; i < MAXGAME; i++) {
  65. pthread_mutex_lock(&gameMutex[i]);
  66. //Regarde si la game est active et le nom
  67. if (game[i].active && strncmp(game[i].name, name, strlen(game[i].name)) == 0) {
  68. index = i;
  69. pthread_mutex_unlock(&gameMutex[i]);
  70. break;
  71. }
  72. pthread_mutex_unlock(&gameMutex[i]);
  73. }
  74. return index;
  75. }
  76. /* --- Fonctions publiques --- */
  77. void ini_handler() {
  78. //Get
  79. add_handler("GET", "game/list", handler_game_list);
  80. //Post
  81. add_handler("POST", "client/end", handler_client_end);
  82. add_handler("POST", "game/create", handler_game_create);
  83. add_handler("POST", "game/join", handler_game_join);
  84. add_handler("POST", "game/quit", handler_game_quit);
  85. add_handler("POST", "player/move", handler_player_move);
  86. add_handler("POST", "object/new", handler_object_new);
  87. }
  88. int handler_client_end(int cliId, JsonParser* json) {
  89. //Verif que le client est toujours actif
  90. if (get_client(cliId) != NULL) {
  91. printf("Deconnexion du client %d\n", cliId);
  92. handler_game_quit(cliId, json);
  93. remove_client(cliId);
  94. }
  95. return SUCCESS;
  96. }
  97. int handler_game_list(int cliId, JsonParser* json) {
  98. JsonEncoder reponse;
  99. JsonArray game;
  100. JsonArray map;
  101. int nb;
  102. //Recup la liste des parties et des cartes
  103. ini_array_encoder(&game);
  104. ini_array_encoder(&map);
  105. nb = list_game(&game);
  106. list_map(&map);
  107. //Creation reponse
  108. ini_encoder(&reponse);
  109. add_string(&reponse, "action", "game/list");
  110. add_integer(&reponse, "status", 200);
  111. add_string(&reponse, "message", "ok");
  112. if (nb == 0) {
  113. add_integer(&reponse, "numberGameList", 0);
  114. } else {
  115. add_integer(&reponse, "numberGameList", nb);
  116. add_array(&reponse, "games", &game);
  117. }
  118. add_array(&reponse, "maps", &map);
  119. //Envoi reponse au client
  120. if (!send_client(cliId, &reponse)) {
  121. adderror("Impossible de répondre au client");
  122. return FAIL;
  123. }
  124. //Nettoyage
  125. clean_json_encoder(&reponse);
  126. clean_json_array(&map);
  127. clean_json_array(&game);
  128. return SUCCESS;
  129. }
  130. int handler_game_create(int cliId, JsonParser* json) {
  131. char* map, * name, * msg;
  132. int index, joueur;
  133. JsonEncoder reponse;
  134. //Verification arguments
  135. if (get_pos(json, "name") == JSON_ERROR) {
  136. send_err_client(cliId, EREQUEST);
  137. adderror("Le json du client est incorrect");
  138. return FAIL;
  139. }
  140. if (get_pos(json, "map") == JSON_ERROR) {
  141. send_err_client(cliId, EREQUEST);
  142. adderror("Le json du client est incorrect");
  143. return FAIL;
  144. }
  145. //Recup valeur
  146. map = get_string(json, "map");
  147. name = get_string(json, "name");
  148. //Initialisation reponse JSON
  149. ini_encoder(&reponse);
  150. add_string(&reponse, "action", "game/create");
  151. //Verif nom non existant
  152. if (search_game(name) != ERR) {
  153. add_integer(&reponse, "status", 501);
  154. add_string(&reponse, "message", "Cannot create game");
  155. if (!send_client(cliId, &reponse)) {
  156. adderror("Impossible de répondre au client");
  157. }
  158. clean_json_encoder(&reponse);
  159. return FAIL;
  160. }
  161. //Creation
  162. index = create_game(name, map);
  163. if (index == ERR) {
  164. add_integer(&reponse, "status", 501);
  165. add_string(&reponse, "message", "Cannot create game");
  166. if (!send_client(cliId, &reponse)) {
  167. adderror("Impossible de répondre au client");
  168. }
  169. clean_json_encoder(&reponse);
  170. return FAIL;
  171. }
  172. //Ajout du joueur dans la partie
  173. joueur = add_player(&game[index], cliId);
  174. if (joueur == ERR) {
  175. stop_game(&game[index]);
  176. add_integer(&reponse, "status", 501);
  177. add_string(&reponse, "message", "Cannot create game");
  178. if (!send_client(cliId, &reponse)) {
  179. adderror("Impossible de répondre au client");
  180. }
  181. clean_json_encoder(&reponse);
  182. return FAIL;
  183. }
  184. //Recup info
  185. describe_game(&game[index], joueur, &reponse);
  186. //Ajout infos
  187. msg = new_string(25 + strlen(map));
  188. sprintf(msg, "Game created with %s", map);
  189. add_integer(&reponse, "status", 201);
  190. add_string(&reponse, "message", msg);
  191. add_string(&reponse, "startPos", "1,1");
  192. free(msg);
  193. //Envoi
  194. if (!send_client(cliId, &reponse)) {
  195. adderror("Impossible de répondre au client");
  196. clean_json_encoder(&reponse);
  197. return FAIL;
  198. }
  199. //Nettoyage
  200. clean_json_encoder(&reponse);
  201. free(map);
  202. free(name);
  203. return SUCCESS;
  204. }
  205. int handler_game_join(int cliId, JsonParser* json) {
  206. char* name;
  207. int index, joueur;
  208. JsonEncoder reponse;
  209. //Verification arguments
  210. if (get_pos(json, "name") == JSON_ERROR) {
  211. send_err_client(cliId, EREQUEST);
  212. adderror("Le json du client est incorrect");
  213. return FAIL;
  214. }
  215. //Recup valeur
  216. name = get_string(json, "name");
  217. //Initialisation json reponse
  218. ini_encoder(&reponse);
  219. add_string(&reponse, "action", "game/join");
  220. //Verif game existe
  221. index = search_game(name);
  222. if (index == ERR) {
  223. add_integer(&reponse, "status", 501);
  224. add_string(&reponse, "message", "Cannot join the game");
  225. if (!send_client(cliId, &reponse)) {
  226. adderror("Impossible de répondre au client");
  227. }
  228. clean_json_encoder(&reponse);
  229. free(name);
  230. return FAIL;
  231. }
  232. //Ajout du joueur dans la partie
  233. joueur = add_player(&game[index], cliId);
  234. if (joueur == ERR) {
  235. add_integer(&reponse, "status", 501);
  236. add_string(&reponse, "message", "Cannot join the game");
  237. if (!send_client(cliId, &reponse)) {
  238. adderror("Impossible de répondre au client");
  239. }
  240. clean_json_encoder(&reponse);
  241. free(name);
  242. return FAIL;
  243. }
  244. //Recup info
  245. describe_game(&game[index], joueur, &reponse);
  246. //Ajout infos
  247. add_integer(&reponse, "status", 201);
  248. add_string(&reponse, "startPos", "1,1");
  249. //Envoi
  250. if (!send_client(cliId, &reponse)) {
  251. adderror("Impossible de répondre au client");
  252. clean_json_encoder(&reponse);
  253. free(name);
  254. return FAIL;
  255. }
  256. //Nettoyage
  257. clean_json_encoder(&reponse);
  258. free(name);
  259. //Avertit les autres joueurs
  260. add_integer(&reponse, "id", cliId);
  261. add_string(&reponse, "pos", "0,0");
  262. notify_player(&game[index], "POST", "game/newplayer", &reponse, cliId);
  263. //Nettoyage
  264. clean_json_encoder(&reponse);
  265. return SUCCESS;
  266. }
  267. int handler_game_quit(int cliId, JsonParser* json) {
  268. boolean find = false;
  269. JsonEncoder notif;
  270. //Cherche le client dans les parties
  271. for (int i = 0; i < MAXGAME; i++) {
  272. pthread_mutex_lock(&gameMutex[i]);
  273. if (game[i].active) {
  274. for (int j = 0; j < MAXPLAYER; j++) {
  275. pthread_mutex_lock(&playerMutex[(i * MAXPLAYER) + j]);
  276. if (game[i].player[j]->ini && game[i].player[j]->id == cliId) {
  277. pthread_mutex_unlock(&playerMutex[(i * MAXPLAYER) + j]);
  278. pthread_mutex_unlock(&gameMutex[i]);
  279. find = true;
  280. remove_player(&game[i], j);
  281. //Avertit les autres joueurs
  282. ini_encoder(&notif);
  283. add_integer(&notif, "player", cliId);
  284. notify_player(&game[i], "POST", "game/quit", &notif, cliId);
  285. clean_json_encoder(&notif);
  286. break;
  287. }
  288. pthread_mutex_unlock(&playerMutex[(i * MAXPLAYER) + j]);
  289. }
  290. if (find) {
  291. break;
  292. }
  293. }
  294. pthread_mutex_unlock(&gameMutex[i]);
  295. }
  296. return SUCCESS;
  297. }
  298. int handler_player_move(int cliId, JsonParser* json) {
  299. char* move;
  300. int index, x = 0, y = 0;
  301. Player* p = NULL;
  302. boolean ok = false, mine = false;
  303. JsonEncoder reponse;
  304. //Verification arguments
  305. if (get_pos(json, "move") == JSON_ERROR) {
  306. return FAIL;
  307. }
  308. //Recup valeur
  309. move = get_string(json, "move");
  310. //Verif game existe
  311. index = search_client_game(cliId);
  312. if (index == ERR) {
  313. free(move);
  314. adderror("La game du client n'existe pas");
  315. return FAIL;
  316. }
  317. //Recup le joueur
  318. pthread_mutex_lock(&gameMutex[index]);
  319. for (int i = 0; i < MAXPLAYER; i++) {
  320. pthread_mutex_lock(&playerMutex[(index * MAXPLAYER) + i]);
  321. if (game[index].player[i]->ini && game[index].player[i]->id == cliId) {
  322. p = game[index].player[i];
  323. pthread_mutex_unlock(&playerMutex[(index * MAXPLAYER) + i]);
  324. break;
  325. }
  326. pthread_mutex_unlock(&playerMutex[(index * MAXPLAYER) + i]);
  327. }
  328. if (p == NULL) {
  329. pthread_mutex_unlock(&gameMutex[index]);
  330. free(move);
  331. adderror("Aucun joueur associé au client");
  332. return FAIL;
  333. }
  334. //Regarde si le joueur peut bouger
  335. if (strncmp(move, "up", 2) == 0) {
  336. if (p->y > 0 && !player_collision(&game[index], p->x, p->y - 1) && (game[index].map[p->x][p->y - 1] == '_' /*Vide*/ || game[index].map[p->x][p->y - 1] == '2' /*Mine*/)) {
  337. ok = true;
  338. //Bouge le joueur sur la carte
  339. p->y--;
  340. //Si marche sur une mine
  341. if (game[index].map[p->x][p->y] == '2') {
  342. game[index].map[p->x][p->y] = '_';
  343. mine = true;
  344. x = p->x;
  345. y = p->y;
  346. }
  347. }
  348. } else if (strncmp(move, "down", 4) == 0) {
  349. if (p->y < game[index].height && !player_collision(&game[index], p->x, p->y + 1) && (game[index].map[p->x][p->y + 1] == '_' /*Vide*/ || game[index].map[p->x][p->y + 1] == '2' /*Mine*/)) {
  350. ok = true;
  351. //Bouge le joueur sur la carte
  352. p->y++;
  353. //Si marche sur une mine
  354. if (game[index].map[p->x][p->y] == '2') {
  355. game[index].map[p->x][p->y] = '_';
  356. mine = true;
  357. x = p->x;
  358. y = p->y;
  359. }
  360. }
  361. } else if (strncmp(move, "left", 4) == 0) {
  362. if (p->x > 0 && !player_collision(&game[index], p->x - 1, p->y) && (game[index].map[p->x - 1][p->y] == '_' /*Vide*/ || game[index].map[p->x - 1][p->y] == '2' /*Mine*/)) {
  363. ok = true;
  364. //Bouge le joueur sur la carte
  365. p->x--;
  366. //Si marche sur une mine
  367. if (game[index].map[p->x][p->y] == '2') {
  368. game[index].map[p->x][p->y] = '_';
  369. mine = true;
  370. x = p->x;
  371. y = p->y;
  372. }
  373. }
  374. } else if (strncmp(move, "right", 4) == 0) {
  375. if (p->x < game[index].width && !player_collision(&game[index], p->x + 1, p->y) && (game[index].map[p->x + 1][p->y] == '_' /*Vide*/ || game[index].map[p->x + 1][p->y] == '2' /*Mine*/)) {
  376. ok = true;
  377. //Bouge le joueur sur la carte
  378. p->x++;
  379. //Si marche sur une mine
  380. if (game[index].map[p->x][p->y] == '2') {
  381. game[index].map[p->x][p->y] = '_';
  382. mine = true;
  383. x = p->x;
  384. y = p->y;
  385. }
  386. }
  387. } else {
  388. pthread_mutex_unlock(&gameMutex[index]);
  389. free(move);
  390. adderror("Le json du client est incorrect");
  391. return FAIL;
  392. }
  393. pthread_mutex_unlock(&gameMutex[index]);
  394. //Notifie les joueurs si mouvement ok
  395. if (ok) {
  396. ini_encoder(&reponse);
  397. add_integer(&reponse, "player", cliId);
  398. add_string(&reponse, "move", move);
  399. notify_player(&game[index], "POST", "player/position/update", &reponse, -1);
  400. //Si marche sur une mine
  401. if (mine) {
  402. printf("Mine %d %d", x, y);
  403. }
  404. }
  405. //Nettoyage
  406. clean_json_encoder(&reponse);
  407. free(move);
  408. return SUCCESS;
  409. }
  410. int handler_object_new(int cliId, JsonParser* json) {
  411. char* class;
  412. int index, type, length, playerIndex = 0;
  413. Player* p = NULL;
  414. obj_node* objn;
  415. JsonEncoder reponse;
  416. //Verification arguments
  417. if (get_pos(json, "class") == JSON_ERROR) {
  418. send_err_client(cliId, EREQUEST);
  419. adderror("Le json du client est incorrect");
  420. return FAIL;
  421. }
  422. //Recup valeur
  423. class = get_string(json, "class");
  424. //Verif valeur class
  425. length = strlen(class);
  426. if (strncmp(class, "classic", length) == 0) {
  427. type = OBJ_BCLASSIC;
  428. } else if (strncmp(class, "mine", length) == 0) {
  429. type = OBJ_BMINE;
  430. } else if (strncmp(class, "remote", length) == 0) {
  431. type = OBJ_BREMOTE;
  432. } else if (strncmp(class, "bomb_up", length) == 0) {
  433. type = OBJ_BOMBUP;
  434. } else if (strncmp(class, "bomb_down", length) == 0) {
  435. type = OBJ_BOMBDOWN;
  436. } else if (strncmp(class, "fire_power", length) == 0) {
  437. type = OBJ_FIREPOWER;
  438. } else if (strncmp(class, "scooter", length) == 0) {
  439. type = OBJ_SCOOTER;
  440. } else if (strncmp(class, "broken_legs", length) == 0) {
  441. type = OBJ_BROKENLEG;
  442. } else if (strncmp(class, "life_up", length) == 0) {
  443. type = OBJ_LIFEUP;
  444. } else if (strncmp(class, "life_max", length) == 0) {
  445. type = OBJ_LIFEMAX;
  446. } else if (strncmp(class, "major", length) == 0) {
  447. type = OBJ_MAJOR;
  448. } else {
  449. free(class);
  450. send_err_client(cliId, EREQUEST);
  451. adderror("Le json du client est incorrect");
  452. return FAIL;
  453. }
  454. //Verif game existe
  455. index = search_client_game(cliId);
  456. if (index == ERR) {
  457. free(class);
  458. send_err_client(cliId, EREQUEST);
  459. adderror("La game du client n'existe pas");
  460. return FAIL;
  461. }
  462. //Recup le joueur
  463. pthread_mutex_lock(&gameMutex[index]);
  464. for (int i = 0; i < MAXPLAYER; i++) {
  465. pthread_mutex_lock(&playerMutex[(index * MAXPLAYER) + i]);
  466. if (game[index].player[i]->ini && game[index].player[i]->id == cliId) {
  467. playerIndex = i;
  468. p = game[index].player[i];
  469. pthread_mutex_unlock(&playerMutex[(index * MAXPLAYER) + i]);
  470. break;
  471. }
  472. pthread_mutex_unlock(&playerMutex[(index * MAXPLAYER) + i]);
  473. }
  474. if (p == NULL) {
  475. pthread_mutex_unlock(&gameMutex[index]);
  476. free(class);
  477. adderror("Aucun joueur associé au client");
  478. return FAIL;
  479. }
  480. //Initialisation json
  481. ini_encoder(&reponse);
  482. add_string(&reponse, "action", "object/new");
  483. //Regarde si un objet correspond
  484. objn = object_search(game[index].object, type, p->x, p->y);
  485. if (objn == NULL) {
  486. add_integer(&reponse, "status", 501);
  487. add_string(&reponse, "message", "No object");
  488. //Envoi
  489. if (!send_client(cliId, &reponse)) {
  490. adderror("Impossible de répondre au client");
  491. clean_json_encoder(&reponse);
  492. free(class);
  493. return FAIL;
  494. }
  495. } else {
  496. //Ajoute l'objet au joueur
  497. pthread_mutex_lock(&playerMutex[(index * MAXPLAYER) + playerIndex]);
  498. add_player_object(p, type);
  499. //Creation reponse
  500. add_integer(&reponse, "status", 201);
  501. describe_player(p, &reponse);
  502. pthread_mutex_unlock(&playerMutex[(index * MAXPLAYER) + playerIndex]);
  503. //Envoi
  504. if (!send_client(cliId, &reponse)) {
  505. adderror("Impossible de répondre au client");
  506. clean_json_encoder(&reponse);
  507. free(class);
  508. return FAIL;
  509. }
  510. //Si major lance le timer pour avertir de la fin
  511. if(type == OBJ_MAJOR){
  512. delay(TIMEMAJOR, index, playerIndex, callback_major_end);
  513. }
  514. }
  515. //Nettoyage
  516. pthread_mutex_unlock(&gameMutex[index]);
  517. free(class);
  518. clean_json_encoder(&reponse);
  519. return SUCCESS;
  520. }