game.c 10 KB

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