game.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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. game[index].object = malloc(sizeof(Object));
  170. object_ini(game[index].object);
  171. pthread_mutex_unlock(&gameMutex[index]);
  172. //Retourne la position de la partie dans le tableau
  173. nbGame++;
  174. free(path);
  175. free(size);
  176. return index;
  177. }
  178. int add_player(Game* g, int cliId) {
  179. int index = 0;
  180. Client* cli;
  181. //Verif que la game n'est pas deja pleine
  182. pthread_mutex_lock(&gameMutex[g->index]);
  183. if (g->nbPlayer >= MAXPLAYER) {
  184. pthread_mutex_unlock(&gameMutex[g->index]);
  185. return ERR;
  186. }
  187. //Cherche un joueur non initialisé
  188. while (index < MAXPLAYER) {
  189. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]);
  190. if (!g->player[index]->ini) {
  191. break;
  192. }
  193. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  194. index++;
  195. }
  196. //Recup du client
  197. cli = get_client(cliId);
  198. if (cli == NULL) {
  199. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  200. pthread_mutex_unlock(&gameMutex[g->index]);
  201. return ERR;
  202. }
  203. //Creation du joueur
  204. create_player(g->player[index], cli);
  205. g->nbPlayer++;
  206. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
  207. pthread_mutex_unlock(&gameMutex[g->index]);
  208. return index;
  209. }
  210. void describe_game(Game* g, int playerIndex, JsonEncoder* desc) {
  211. JsonEncoder player;
  212. JsonEncoder map;
  213. JsonArray players;
  214. char* content;
  215. //Initialisation
  216. ini_encoder(&player);
  217. ini_encoder(&map);
  218. ini_array_encoder(&players);
  219. //Info map
  220. pthread_mutex_lock(&gameMutex[g->index]);
  221. content = remove_char(g->mapContent, '\n'); //La map sans \n car interdit en JSON
  222. add_integer(&map, "width", g->width);
  223. add_integer(&map, "height", g->height);
  224. add_string(&map, "content", content);
  225. free(content);
  226. //Ajout info
  227. add_integer(desc, "nbPlayers", g->nbPlayer);
  228. add_object(desc, "map", &map);
  229. //Ajout info courte joueur
  230. //printf("Add players\n");
  231. for (int i = 0; i < MAXPLAYER; i++) {
  232. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]);
  233. if (g->player[i]->ini) {
  234. describe_short_player(g->player[i], &player);
  235. add_array_object(&players, &player);
  236. clean_json_encoder(&player);
  237. }
  238. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
  239. }
  240. //printf("Fin Add players\n");
  241. add_array(desc, "players", &players);
  242. //Si besoins ajout un joueur
  243. if (playerIndex >= 0 && playerIndex < MAXPLAYER) {
  244. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
  245. if (g->player[playerIndex]->ini) {
  246. describe_player(g->player[playerIndex], &player);
  247. add_object(desc, "player", &player);
  248. clean_json_encoder(&player);
  249. }
  250. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
  251. }
  252. //Nettoyage
  253. pthread_mutex_unlock(&gameMutex[g->index]);
  254. clean_json_encoder(&map);
  255. clean_json_array(&players);
  256. }
  257. boolean notify_player(Game* g, char* method, char* ressource, JsonEncoder* param, int excludePlayerId) {
  258. boolean res = true;
  259. pthread_mutex_lock(&gameMutex[g->index]);
  260. //Regarde si la game est active
  261. if (!g->active) {
  262. pthread_mutex_unlock(&gameMutex[g->index]);
  263. return false;
  264. }
  265. //Parcours les joeurs de la game
  266. for (int i = 0; i < MAXPLAYER; i++) {
  267. //Si joueur actif
  268. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]);
  269. if (g->player[i]->ini && g->player[i]->id != excludePlayerId) {
  270. res = res && notify_client(g->player[i]->cli, method, ressource, param);
  271. }
  272. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
  273. }
  274. pthread_mutex_unlock(&gameMutex[g->index]);
  275. return res;
  276. }
  277. boolean player_collision(Game* g, int x, int y) {
  278. for (int i = 0; i < MAXPLAYER; i++) {
  279. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]);
  280. if (g->player[i]->ini) {
  281. if (g->player[i]->x == x && g->player[i]->y == y) {
  282. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
  283. return true;
  284. }
  285. }
  286. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
  287. }
  288. return false;
  289. }
  290. void remove_player(Game* g, int playerIndex) {
  291. pthread_mutex_lock(&gameMutex[g->index]);
  292. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
  293. g->nbPlayer--;
  294. delete_player(g->player[playerIndex]);
  295. pthread_mutex_unlock(&gameMutex[g->index]);
  296. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
  297. }
  298. void stop_game(Game* g) {
  299. pthread_mutex_lock(&gameMutex[g->index]);
  300. //Indique comme inactive
  301. g->active = false;
  302. //Suppr les joueurs
  303. for (int i = 0; i < MAXPLAYER; i++) {
  304. pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]);
  305. if (g->player[i]->ini) {
  306. delete_player(g->player[i]);
  307. }
  308. free(g->player[i]);
  309. pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
  310. }
  311. //Libere la memoire
  312. for (int i = 0; i < g->width; i++) {
  313. free(g->map[i]);
  314. }
  315. free(g->map);
  316. free(g->mapName);
  317. free(g->mapContent);
  318. pthread_mutex_unlock(&gameMutex[g->index]);
  319. //Retire une game
  320. nbGame--;
  321. }
  322. void clean_games() {
  323. for (int i = 0; i < MAXGAME; i++) {
  324. if (game[i].active) {
  325. stop_game(&game[i]);
  326. }
  327. }
  328. }