game.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /*
  2. * File: game.c
  3. * Author: Arthur Brandao
  4. *
  5. * Created on 28 novembre 2018
  6. */
  7. #define _XOPEN_SOURCE 500
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include "error.h"
  11. #include "str.h"
  12. #include "file.h"
  13. #include "game.h"
  14. #include "bomberstudent_server.h"
  15. /* --- Extern --- */
  16. Game game[MAXGAME];
  17. int nbGame = 0;
  18. pthread_mutex_t gameMutex[MAXGAME];
  19. pthread_mutex_t playerMutex[MAXGAME * MAXPLAYER];
  20. /* --- Fonctions privées --- */
  21. /**
  22. * Transforme le fichier map en un tableau 2D
  23. * @param char* Le contenu du fichier map
  24. * @param int Largeur de la map
  25. * @param int Hauteur de la map
  26. * @return char** La map parser
  27. */
  28. char** parse_map(char* mapContent, int width, int height) {
  29. char** map = malloc(sizeof (char*) * width);
  30. //Creation des colonnes
  31. for (int i = 0; i < width; i++) {
  32. map[i] = malloc(sizeof (char) * height);
  33. }
  34. //Remplissage
  35. for (int i = 0; i < height; i++) {
  36. for (int j = 0; j < width; j++) {
  37. map[j][i] = *mapContent;
  38. mapContent++;
  39. }
  40. mapContent++;
  41. }
  42. return map;
  43. }
  44. /* --- Fonctions publiques --- */
  45. boolean ini_games() {
  46. //Ini les games
  47. for (int i = 0; i < MAXGAME; i++) {
  48. game[i].active = false;
  49. game[i].index = i;
  50. }
  51. //Ini les mutex des games
  52. for (int i = 0; i < MAXGAME; i++) {
  53. if (pthread_mutex_init(&gameMutex[i], NULL) != 0) {
  54. adderror("Impossible d'initialiser les mutex des games");
  55. return false;
  56. }
  57. }
  58. //Ini les mutex des joueurs des games
  59. for (int i = 0; i < MAXGAME * MAXPLAYER; i++) {
  60. if (pthread_mutex_init(&playerMutex[i], NULL) != 0) {
  61. adderror("Impossible d'initialiser les mutex des joueurs");
  62. return false;
  63. }
  64. }
  65. return true;
  66. }
  67. void list_map(JsonArray* res) {
  68. char** result;
  69. int nbResult;
  70. //Regarde les fichiers dans le dossier
  71. result = file_list(MAPDIR, &nbResult);
  72. for (int i = 0; i < nbResult; i++) {
  73. add_array_string(res, result[i]);
  74. free(result[i]);
  75. }
  76. free(result);
  77. }
  78. int list_game(JsonArray* res) {
  79. JsonEncoder gameJson;
  80. int compteur = 0, i = 0;
  81. //Si il n' y a aucune game
  82. if (nbGame == 0) {
  83. return 0;
  84. }
  85. //Initialisation json
  86. ini_encoder(&gameJson);
  87. //Ajoute chaque game
  88. while (compteur < nbGame && i < MAXGAME) {
  89. pthread_mutex_lock(&gameMutex[i]);
  90. if (!game[i].active) {
  91. pthread_mutex_unlock(&gameMutex[i]);
  92. i++;
  93. continue;
  94. }
  95. //Creation objet json
  96. add_string(&gameJson, "name", game[i].name);
  97. add_integer(&gameJson, "nbPlayer", game[i].nbPlayer);
  98. add_string(&gameJson, "map", game[i].mapName);
  99. //Ajout dans le tableau
  100. add_array_object(res, &gameJson);
  101. //Nettoyage encoder objet
  102. clean_json_encoder(&gameJson);
  103. //Incremente
  104. pthread_mutex_unlock(&gameMutex[i]);
  105. i++;
  106. compteur++;
  107. }
  108. return nbGame;
  109. }
  110. int* map_size(char* map) {
  111. int* res;
  112. res = malloc(sizeof (int) * 2);
  113. res[WIDTH] = 0;
  114. res[HEIGHT] = 1;
  115. //Parcours la 1er ligne pour compter le nombre de caractère
  116. while (*map != '\n' && *map != '\0') {
  117. res[WIDTH]++;
  118. map++;
  119. }
  120. if (*map == '\0') {
  121. return res;
  122. }
  123. //Compte les lignes
  124. map++;
  125. while (*map != '\0') {
  126. if (*map == '\n') {
  127. res[HEIGHT]++;
  128. }
  129. map++;
  130. }
  131. return res;
  132. }
  133. int create_game(char* name, char* map) {
  134. int length, index = 0;
  135. char* path;
  136. int* size;
  137. //Regarde si il reste une game de disponnible
  138. if (nbGame == MAXGAME) {
  139. return ERR;
  140. }
  141. //Cherche une game libre
  142. while (index < MAXGAME) {
  143. pthread_mutex_lock(&gameMutex[index]);
  144. if (game[index].active == false) {
  145. break;
  146. }
  147. pthread_mutex_unlock(&gameMutex[index]);
  148. index++;
  149. }
  150. //Recup la map
  151. length = strlen(MAPDIR) + strlen(map);
  152. path = new_string(length);
  153. snprintf(path, length + 1, "%s%s", MAPDIR, map);
  154. game[index].mapContent = file_get_content(path);
  155. //Calcul taille de la map
  156. size = map_size(game[index].mapContent);
  157. //Set Up
  158. game[index].active = true;
  159. game[index].name = string_copy(name);
  160. game[index].nbPlayer = 0;
  161. game[index].mapName = string_copy(map);
  162. game[index].width = size[WIDTH];
  163. game[index].height = size[HEIGHT];
  164. game[index].map = parse_map(game[index].mapContent, size[WIDTH], size[HEIGHT]);
  165. for (int i = 0; i < MAXPLAYER; i++) {
  166. game[index].player[i] = malloc(sizeof (Player));
  167. game[index].player[i]->ini = false;
  168. }
  169. pthread_mutex_unlock(&gameMutex[index]);
  170. //Retourne la position de la partie dans le tableau
  171. nbGame++;
  172. free(path);
  173. free(size);
  174. return index;
  175. }
  176. int add_player(Game* g, int cliId) {
  177. int index = 0;
  178. Client* cli;
  179. //Verif que la game n'est pas deja pleine
  180. pthread_mutex_lock(&gameMutex[g->index]);
  181. if (g->nbPlayer >= MAXPLAYER) {
  182. pthread_mutex_unlock(&gameMutex[g->index]);
  183. return ERR;
  184. }
  185. //Cherche un joueur non initialisé
  186. while (index < MAXPLAYER) {
  187. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]);
  188. if (!g->player[index]->ini) {
  189. break;
  190. }
  191. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  192. index++;
  193. }
  194. //Recup du client
  195. cli = get_client(cliId);
  196. if (cli == NULL) {
  197. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  198. pthread_mutex_unlock(&gameMutex[g->index]);
  199. return ERR;
  200. }
  201. //Creation du joueur
  202. create_player(g->player[index], cli);
  203. g->nbPlayer++;
  204. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  205. pthread_mutex_unlock(&gameMutex[g->index]);
  206. return index;
  207. }
  208. void describe_game(Game* g, int playerIndex, JsonEncoder* desc) {
  209. JsonEncoder player;
  210. JsonEncoder map;
  211. JsonArray players;
  212. char* content;
  213. //Initialisation
  214. ini_encoder(&player);
  215. ini_encoder(&map);
  216. ini_array_encoder(&players);
  217. //Info map
  218. pthread_mutex_lock(&gameMutex[g->index]);
  219. content = remove_char(g->mapContent, '\n'); //La map sans \n car interdit en JSON
  220. add_integer(&map, "width", g->width);
  221. add_integer(&map, "height", g->height);
  222. add_string(&map, "content", content);
  223. free(content);
  224. //Ajout info
  225. add_integer(desc, "nbPlayers", g->nbPlayer);
  226. add_object(desc, "map", &map);
  227. //Ajout info courte joueur
  228. //printf("Add players\n");
  229. for (int i = 0; i < MAXPLAYER; i++) {
  230. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]);
  231. if (g->player[i]->ini) {
  232. describe_short_player(g->player[i], &player);
  233. add_array_object(&players, &player);
  234. clean_json_encoder(&player);
  235. }
  236. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
  237. }
  238. //printf("Fin Add players\n");
  239. add_array(desc, "players", &players);
  240. //Si besoins ajout un joueur
  241. if (playerIndex >= 0 && playerIndex < MAXPLAYER) {
  242. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
  243. if (g->player[playerIndex]->ini) {
  244. describe_player(g->player[playerIndex], &player);
  245. add_object(desc, "player", &player);
  246. clean_json_encoder(&player);
  247. }
  248. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
  249. }
  250. //Nettoyage
  251. pthread_mutex_unlock(&gameMutex[g->index]);
  252. clean_json_encoder(&map);
  253. clean_json_array(&players);
  254. }
  255. boolean notify_player(Game* g, char* method, char* ressource, JsonEncoder* param, int excludePlayerId) {
  256. boolean res = true;
  257. pthread_mutex_lock(&gameMutex[g->index]);
  258. //Regarde si la game est active
  259. if (!g->active) {
  260. pthread_mutex_unlock(&gameMutex[g->index]);
  261. return false;
  262. }
  263. //Parcours les joeurs de la game
  264. for (int i = 0; i < MAXPLAYER; i++) {
  265. //Si joueur actif
  266. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]);
  267. if (g->player[i]->ini && g->player[i]->id != excludePlayerId) {
  268. res = res && notify_client(g->player[i]->cli, method, ressource, param);
  269. }
  270. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
  271. }
  272. pthread_mutex_unlock(&gameMutex[g->index]);
  273. return res;
  274. }
  275. boolean player_collision(Game* g, int x, int y) {
  276. for (int i = 0; i < MAXPLAYER; i++) {
  277. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]);
  278. if (g->player[i]->ini) {
  279. if (g->player[i]->x == x && g->player[i]->y == y) {
  280. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
  281. return true;
  282. }
  283. }
  284. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
  285. }
  286. return false;
  287. }
  288. void remove_player(Game* g, int playerIndex) {
  289. pthread_mutex_lock(&gameMutex[g->index]);
  290. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
  291. g->nbPlayer--;
  292. delete_player(g->player[playerIndex]);
  293. pthread_mutex_unlock(&gameMutex[g->index]);
  294. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
  295. }
  296. void stop_game(Game* g) {
  297. pthread_mutex_lock(&gameMutex[g->index]);
  298. //Indique comme inactive
  299. g->active = false;
  300. //Suppr les joueurs
  301. for (int i = 0; i < MAXPLAYER; i++) {
  302. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]);
  303. if (g->player[i]->ini) {
  304. delete_player(g->player[i]);
  305. }
  306. free(g->player[i]);
  307. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
  308. }
  309. //Libere la memoire
  310. for (int i = 0; i < g->width; i++) {
  311. free(g->map[i]);
  312. }
  313. free(g->map);
  314. free(g->mapName);
  315. free(g->mapContent);
  316. pthread_mutex_unlock(&gameMutex[g->index]);
  317. //Retire une game
  318. nbGame--;
  319. }
  320. void clean_games() {
  321. for (int i = 0; i < MAXGAME; i++) {
  322. if (game[i].active) {
  323. stop_game(&game[i]);
  324. }
  325. }
  326. }