/* * File: game.c * Author: Arthur Brandao * * Created on 28 novembre 2018 */ #define _XOPEN_SOURCE 500 #include #include #include "error.h" #include "str.h" #include "file.h" #include "game.h" #include "bomberstudent_server.h" /* --- Extern --- */ Game game[MAXGAME]; int nbGame = 0; pthread_mutex_t gameMutex[MAXGAME]; pthread_mutex_t playerMutex[MAXGAME * MAXPLAYER]; /* --- Fonctions privées --- */ /** * Transforme le fichier map en un tableau 2D * @param char* Le contenu du fichier map * @param int Largeur de la map * @param int Hauteur de la map * @return char** La map parser */ char** parse_map(char* mapContent, int width, int height) { char** map = malloc(sizeof (char*) * width); //Creation des colonnes for (int i = 0; i < width; i++) { map[i] = malloc(sizeof (char) * height); } //Remplissage for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { map[j][i] = *mapContent; mapContent++; } mapContent++; } return map; } /* --- Fonctions publiques --- */ boolean ini_games() { //Ini les games for (int i = 0; i < MAXGAME; i++) { game[i].active = false; game[i].index = i; } //Ini les mutex des games for (int i = 0; i < MAXGAME; i++) { if (pthread_mutex_init(&gameMutex[i], NULL) != 0) { adderror("Impossible d'initialiser les mutex des games"); return false; } } //Ini les mutex des joueurs des games for (int i = 0; i < MAXGAME * MAXPLAYER; i++) { if (pthread_mutex_init(&playerMutex[i], NULL) != 0) { adderror("Impossible d'initialiser les mutex des joueurs"); return false; } } return true; } void list_map(JsonArray* res) { char** result; int nbResult; //Regarde les fichiers dans le dossier result = file_list(MAPDIR, &nbResult); for (int i = 0; i < nbResult; i++) { add_array_string(res, result[i]); free(result[i]); } free(result); } int list_game(JsonArray* res) { JsonEncoder gameJson; int compteur = 0, i = 0; //Si il n' y a aucune game if (nbGame == 0) { return 0; } //Initialisation json ini_encoder(&gameJson); //Ajoute chaque game while (compteur < nbGame && i < MAXGAME) { pthread_mutex_lock(&gameMutex[i]); if (!game[i].active) { pthread_mutex_unlock(&gameMutex[i]); i++; continue; } //Creation objet json add_string(&gameJson, "name", game[i].name); add_integer(&gameJson, "nbPlayer", game[i].nbPlayer); add_string(&gameJson, "map", game[i].mapName); //Ajout dans le tableau add_array_object(res, &gameJson); //Nettoyage encoder objet clean_json_encoder(&gameJson); //Incremente pthread_mutex_unlock(&gameMutex[i]); i++; compteur++; } return nbGame; } int* map_size(char* map) { int* res; res = malloc(sizeof (int) * 2); res[WIDTH] = 0; res[HEIGHT] = 1; //Parcours la 1er ligne pour compter le nombre de caractère while (*map != '\n' && *map != '\0') { res[WIDTH]++; map++; } if (*map == '\0') { return res; } //Compte les lignes map++; while (*map != '\0') { if (*map == '\n') { res[HEIGHT]++; } map++; } return res; } int create_game(char* name, char* map) { int length, index = 0; char* path; int* size; //Regarde si il reste une game de disponnible if (nbGame == MAXGAME) { return ERR; } //Cherche une game libre while (index < MAXGAME) { pthread_mutex_lock(&gameMutex[index]); if (game[index].active == false) { break; } pthread_mutex_unlock(&gameMutex[index]); index++; } //Recup la map length = strlen(MAPDIR) + strlen(map); path = new_string(length); snprintf(path, length + 1, "%s%s", MAPDIR, map); game[index].mapContent = file_get_content(path); //Calcul taille de la map size = map_size(game[index].mapContent); //Set Up game[index].active = true; game[index].name = string_copy(name); game[index].nbPlayer = 0; game[index].mapName = string_copy(map); game[index].width = size[WIDTH]; game[index].height = size[HEIGHT]; game[index].map = parse_map(game[index].mapContent, size[WIDTH], size[HEIGHT]); for (int i = 0; i < MAXPLAYER; i++) { game[index].player[i] = malloc(sizeof (Player)); game[index].player[i]->ini = false; } game[index].object = malloc(sizeof(Object)); object_ini(game[index].object); //object_add(game[index].object, OBJ_MAJOR, 1, 1); pthread_mutex_unlock(&gameMutex[index]); //Retourne la position de la partie dans le tableau nbGame++; free(path); free(size); return index; } int add_player(Game* g, int cliId) { int index = 0; Client* cli; //Verif que la game n'est pas deja pleine pthread_mutex_lock(&gameMutex[g->index]); if (g->nbPlayer >= MAXPLAYER) { pthread_mutex_unlock(&gameMutex[g->index]); return ERR; } //Cherche un joueur non initialisé while (index < MAXPLAYER) { pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]); if (!g->player[index]->ini) { break; } pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]); index++; } //Recup du client cli = get_client(cliId); if (cli == NULL) { pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]); pthread_mutex_unlock(&gameMutex[g->index]); return ERR; } //Creation du joueur create_player(g->player[index], cli); g->nbPlayer++; pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]); pthread_mutex_unlock(&gameMutex[g->index]); return index; } void describe_game(Game* g, int playerIndex, JsonEncoder* desc) { JsonEncoder player; JsonEncoder map; JsonArray players; char* content; //Initialisation ini_encoder(&player); ini_encoder(&map); ini_array_encoder(&players); //Info map pthread_mutex_lock(&gameMutex[g->index]); content = remove_char(g->mapContent, '\n'); //La map sans \n car interdit en JSON add_integer(&map, "width", g->width); add_integer(&map, "height", g->height); add_string(&map, "content", content); free(content); //Ajout info add_integer(desc, "nbPlayers", g->nbPlayer); add_object(desc, "map", &map); //Ajout info courte joueur //printf("Add players\n"); for (int i = 0; i < MAXPLAYER; i++) { pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]); if (g->player[i]->ini) { describe_short_player(g->player[i], &player); add_array_object(&players, &player); clean_json_encoder(&player); } pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]); } //printf("Fin Add players\n"); add_array(desc, "players", &players); //Si besoins ajout un joueur if (playerIndex >= 0 && playerIndex < MAXPLAYER) { pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]); if (g->player[playerIndex]->ini) { describe_player(g->player[playerIndex], &player); add_object(desc, "player", &player); clean_json_encoder(&player); } pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]); } //Nettoyage pthread_mutex_unlock(&gameMutex[g->index]); clean_json_encoder(&map); clean_json_array(&players); } boolean notify_player(Game* g, char* method, char* ressource, JsonEncoder* param, int excludePlayerId) { boolean res = true; pthread_mutex_lock(&gameMutex[g->index]); //Regarde si la game est active if (!g->active) { pthread_mutex_unlock(&gameMutex[g->index]); return false; } //Parcours les joeurs de la game for (int i = 0; i < MAXPLAYER; i++) { //Si joueur actif pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]); if (g->player[i]->ini && g->player[i]->id != excludePlayerId) { res = res && notify_client(g->player[i]->cli, method, ressource, param); } pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]); } pthread_mutex_unlock(&gameMutex[g->index]); return res; } boolean player_collision(Game* g, int x, int y) { for (int i = 0; i < MAXPLAYER; i++) { pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]); if (g->player[i]->ini) { if (g->player[i]->x == x && g->player[i]->y == y) { pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]); return true; } } pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]); } return false; } void remove_player(Game* g, int playerIndex) { pthread_mutex_lock(&gameMutex[g->index]); pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]); g->nbPlayer--; delete_player(g->player[playerIndex]); pthread_mutex_unlock(&gameMutex[g->index]); pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]); } void stop_game(Game* g) { pthread_mutex_lock(&gameMutex[g->index]); //Indique comme inactive g->active = false; //Suppr les joueurs for (int i = 0; i < MAXPLAYER; i++) { pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]); if (g->player[i]->ini) { delete_player(g->player[i]); } free(g->player[i]); pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]); } //Libere la memoire for (int i = 0; i < g->width; i++) { free(g->map[i]); } free(g->map); free(g->mapName); free(g->mapContent); pthread_mutex_unlock(&gameMutex[g->index]); //Retire une game nbGame--; } void clean_games() { for (int i = 0; i < MAXGAME; i++) { if (game[i].active) { stop_game(&game[i]); } } }