123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- /*
- * File: game.c
- * Author: Arthur Brandao
- *
- * Created on 28 novembre 2018
- */
- #define _XOPEN_SOURCE 500
- #include <stdio.h>
- #include <stdlib.h>
- #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);
- 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]);
- }
- }
- }
|