diff --git a/03-network/client/src/defs.h b/03-network/client/src/defs.h index 8e52d45..afe5ef8 100644 --- a/03-network/client/src/defs.h +++ b/03-network/client/src/defs.h @@ -7,6 +7,11 @@ #define SERVER_ADDR "127.0.0.1" #define SERVER_PORT 9080 +// ERRORS +#define STDOK 0 +#define STDERR -1 +#define MEMERR -2 + // SDL2 #define SCREEN_WIDTH 1000 #define SCREEN_HEIGHT 480 diff --git a/03-network/client/src/format.c b/03-network/client/src/format.c new file mode 100644 index 0000000..4700e9a --- /dev/null +++ b/03-network/client/src/format.c @@ -0,0 +1,64 @@ +#include +#include "defs.h" +#include "structs.h" +#include "format.h" + +extern SDL_Texture *idle_animation; +extern SDL_Texture *run_animation; +extern SDL_Texture *jump_animation; +extern struct object *create_object(SDL_Texture *texture, int scale, int resolution); + +int handle_player_connect(int *message, struct object ***map, int *slots) { + int object_id = message[1]; + + if (object_id >= *slots) { + *slots = object_id+1; + *map = realloc(*map, sizeof(struct object *)*(*slots)); + } + + if (*map == NULL) + return MEMERR; + + struct object *new_object = create_object(idle_animation, 4, 48); + if (new_object == NULL) + return MEMERR; + + new_object->id = object_id; + new_object->x = message[2]; + new_object->y = message[3]; + new_object->colliding = message[4]; + new_object->force = message[5]; + new_object->state = message[6]; + (*map)[object_id] = new_object; + + return STDOK; +} + +int handle_object_properties(int *message, struct object ***map, int *slots) { + int object_id = message[1]; + + if (object_id >= *slots) { + *slots = object_id+1; + *map = realloc(*map, sizeof(struct object *)*(*slots)); + } + + if (*map == NULL) + return MEMERR; + + if ((*map)[object_id] == NULL) { + struct object *new_object = create_object(idle_animation, 4, 48); + if (new_object == NULL) + return MEMERR; + + new_object->id = object_id; + (*map)[object_id] = new_object; + } + + (*map)[object_id]->x = message[2]; + (*map)[object_id]->y = message[3]; + (*map)[object_id]->colliding = message[4]; + (*map)[object_id]->force = message[5]; + (*map)[object_id]->state = message[6]; + + return STDOK; +} diff --git a/03-network/client/src/format.h b/03-network/client/src/format.h new file mode 100644 index 0000000..f84065a --- /dev/null +++ b/03-network/client/src/format.h @@ -0,0 +1,9 @@ +#ifndef FORMAT_H +#define FORMAT_H + +#include + +int handle_player_connect(int *message, struct object ***map, int *slots); +int handle_object_properties(int *message, struct object ***map, int *slots); + +#endif diff --git a/03-network/client/src/main.c b/03-network/client/src/main.c index 1dc2cf4..fd48c48 100644 --- a/03-network/client/src/main.c +++ b/03-network/client/src/main.c @@ -4,6 +4,7 @@ #include #include "structs.h" #include "defs.h" +#include "format.h" #define DEBUG 1 @@ -16,15 +17,12 @@ double last_frame; // network TCPsocket server_socket; -// scene -struct object *player; - // textures SDL_Texture *idle_animation; -SDL_Texture *jump_animation; SDL_Texture *run_animation; +SDL_Texture *jump_animation; - +// scene int objects_count = 0; struct object ** objects_map; @@ -75,59 +73,6 @@ SDL_Texture *load_texture(const char *path) { return texture; } -void switch_animation(struct object *object, SDL_Texture *animation) { - if (object->texture == animation) - return; - - object->animation_slide = 0; - object->texture = animation; -} - -struct object *create_object(SDL_Texture *texture, int scale, int resolution) { - struct object *object = (struct object *) calloc(1, sizeof(struct object)); - - if (object == NULL) { - fprintf(stderr, "Error: failed allocating memory for new object\n"); - return NULL; - } - - object->texture = texture; - object->resolution = resolution; - object->animation_speed = 13; - object->scale = scale; - - return object; -} - -void draw_object(struct object *object) { - int texture_width; - SDL_Rect src; - SDL_Rect dest; - - src.x = object->animation_slide * object->resolution; - src.y = 0; - - src.w = object->resolution; - src.h = object->resolution; - - dest.x = object->x; - dest.y = object->y; - dest.w = object->resolution * object->scale; - dest.h = object->resolution * object->scale; - - SDL_RenderCopyEx(game.renderer, object->texture, &src, &dest, 0, NULL, object->flip); - - // update animation slide - SDL_QueryTexture(object->texture, NULL, NULL, &texture_width, NULL); - - object->animation_clock += object->animation_speed*(delta_time/1000); - - if (object->animation_clock >= 1) { - object->animation_clock = 0; - object->animation_slide = (object->animation_slide+1) % (texture_width / object->resolution); // clock arithmetic: jump back to first animation slide - } -} - void present_scene(void) { SDL_RenderPresent(game.renderer); } @@ -168,28 +113,11 @@ int handle_server(void *data) { if (DEBUG) fprintf(stdout, "DEBUG: PLAYER CONNECT MESSAGE\n"); - if (message[1] >= objects_count) { - objects_map = (struct object **) realloc(objects_map, sizeof(struct object *)*message[1]); - objects_count = message[1]+1; + int ret = handle_player_connect(message, &objects_map, &objects_count); + if (ret == MEMERR) { + fprintf(stderr, "MEMERR: Failed handling memory for player connect\n"); + return MEMERR; } - if (objects_map == NULL) { - fprintf(stderr, "Error: failed reallocating objects hash map\n"); - return -1; - } - - struct object *new_object = create_object(idle_animation, 4, 48); - if (new_object == NULL) { - fprintf(stderr, "Error: failed allocating memory for new object\n"); - return -1; - } - - new_object->id = message[1]; - new_object->x = message[2]; - new_object->y = message[3]; - new_object->colliding = message[4]; - new_object->force = message[5]; - new_object->state = message[6]; - objects_map[message[1]] = new_object; continue; } @@ -197,33 +125,13 @@ int handle_server(void *data) { if (message[0] == OBJECT_PROPERTIES_FORMAT) { if (DEBUG) fprintf(stdout, "DEBUG: OBJECT PROPERTIES MESSAGE FOR ID %d\n", message[1]); - - if (message[1] >= objects_count) { - objects_map = (struct object **) realloc(objects_map, sizeof(struct object *)*message[1]); - objects_count = message[1]+1; - } - if (objects_map == NULL) { - fprintf(stderr, "Error: failed reallocating objects hash map\n"); - return -1; + + int ret = handle_object_properties(message, &objects_map, &objects_count); + if (ret == MEMERR) { + fprintf(stderr, "MEMERR: Failed handling memory for new object properties\n"); + return MEMERR; } - if (objects_map[message[1]] == NULL) { - struct object *new_object = create_object(idle_animation, 4, 48); - if (new_object == NULL) { - fprintf(stderr, "Error: failed allocating memory for new object\n"); - return -1; - } - - new_object->id = message[1]; - objects_map[message[1]] = new_object; - } - - objects_map[message[1]]->x = message[2]; - objects_map[message[1]]->y = message[3]; - objects_map[message[1]]->colliding = message[4]; - objects_map[message[1]]->force = message[5]; - - objects_map[message[1]]->state = message[6]; continue; } @@ -334,7 +242,7 @@ int main(int argc, char *argv[]) { if (obj->state & JUMP_MOVEMENT) switch_animation(obj, jump_animation); - draw_object(obj); + draw_object(&game, obj); } present_scene(); diff --git a/03-network/client/src/object.c b/03-network/client/src/object.c new file mode 100644 index 0000000..6be16b5 --- /dev/null +++ b/03-network/client/src/object.c @@ -0,0 +1,54 @@ +#include "structs.h" + +extern double delta_time; + +struct object *create_object(SDL_Texture *texture, int scale, int resolution) { + struct object *object = (struct object *) calloc(1, sizeof(struct object)); + + if (object == NULL) + return NULL; + + object->texture = texture; + object->resolution = resolution; + object->animation_speed = 13; + object->scale = scale; + + return object; +} + +void draw_object(struct game *game, struct object *object) { + int texture_width; + SDL_Rect src; + SDL_Rect dest; + + src.x = object->animation_slide * object->resolution; + src.y = 0; + + src.w = object->resolution; + src.h = object->resolution; + + dest.x = object->x; + dest.y = object->y; + dest.w = object->resolution * object->scale; + dest.h = object->resolution * object->scale; + + SDL_RenderCopyEx(game->renderer, object->texture, &src, &dest, 0, NULL, object->flip); + + // update animation slide + SDL_QueryTexture(object->texture, NULL, NULL, &texture_width, NULL); + + object->animation_clock += object->animation_speed*(delta_time/1000); + + if (object->animation_clock >= 1) { + object->animation_clock = 0; + object->animation_slide = (object->animation_slide+1) % (texture_width / object->resolution); // clock arithmetic: jump back to first animation slide + } +} + +void switch_animation(struct object *object, SDL_Texture *animation) { + if (object->texture == animation) + return; + + object->animation_slide = 0; + object->texture = animation; +} diff --git a/03-network/client/src/structs.h b/03-network/client/src/structs.h index 9717a3e..9700ad1 100644 --- a/03-network/client/src/structs.h +++ b/03-network/client/src/structs.h @@ -22,8 +22,8 @@ struct animation { struct object { SDL_Texture *texture; int resolution; // of the texture/every tile - int id; + int x; int y; int scale; @@ -40,4 +40,8 @@ struct object { int force; }; +struct object *create_object(SDL_Texture *texture, int scale, int resolution); +void draw_object(struct game *game, struct object *object); +void switch_animation(struct object *object, SDL_Texture *animation); + #endif diff --git a/03-network/server/src/defs.h b/03-network/server/src/defs.h index ab1fcf9..bad740a 100644 --- a/03-network/server/src/defs.h +++ b/03-network/server/src/defs.h @@ -5,6 +5,10 @@ #define GENERAL_DEBUG 0x0001 #define PLAYER_DEBUG 0x0010 +// ERRORS +#define STDERR -1 +#define MEMERR -2 + // MCS: Message Communication Standard #define SERVER_MESSAGE_LEN 10 #define CLIENT_MESSAGE_LEN 7 diff --git a/03-network/server/src/hashmap.c b/03-network/server/src/hashmap.c new file mode 100644 index 0000000..7c03681 --- /dev/null +++ b/03-network/server/src/hashmap.c @@ -0,0 +1,43 @@ +#include +#include +#include "hashmap.h" +#include "defs.h" + +int find_empty_slot(void **map, int slots) { + int slot = 0; + + if (slots <= 0) + return slot; + + if (map == NULL) + return slot; + + while (slot < slots) { + if (map[slot] == NULL) + break; + + slot++; + } + + return slot; +} + +int allocate_value(void ***map, int *slots, int bytes) { + int empty_slot = find_empty_slot(*map, *slots); + + if (empty_slot == *slots) { + (*slots)++; + *map = realloc(*map, sizeof(void *)*(*slots)); + } + + if (*map == NULL) + return MEMERR; + + void *new_value = calloc(1, bytes); + if (new_value == NULL) + return MEMERR; + + (*map)[empty_slot] = new_value; + + return empty_slot; +} diff --git a/03-network/server/src/hashmap.h b/03-network/server/src/hashmap.h new file mode 100644 index 0000000..1d97232 --- /dev/null +++ b/03-network/server/src/hashmap.h @@ -0,0 +1,9 @@ +#ifndef HASHMAP_H +#define HASHMAP_H + +#include "structs.h" + +int find_empty_slot(void **map, int slots); +int allocate_value(void ***map, int *slots, int bytes); + +#endif diff --git a/03-network/server/src/main.c b/03-network/server/src/main.c index b0ceb71..e300282 100644 --- a/03-network/server/src/main.c +++ b/03-network/server/src/main.c @@ -4,8 +4,9 @@ #include #include #include -#include "structs.h" #include "defs.h" +#include "structs.h" +#include "hashmap.h" #define DEBUG 0x0010 #define PORT 9080 @@ -44,36 +45,7 @@ void handle_player_physics(struct object *obj) { obj->y += obj->force; } -void send_player_positions(TCPsocket socket, int player_id) { - if (objects_map == NULL) - return; - - for (int iter = 0; iter < objects_count; iter++) { - struct object *obj = objects_map[iter]; - if (obj == NULL) - continue; - - // Update the client with every object's information - // Note: the order OBVIOUSLY matters - int reply[] = { - OBJECT_PROPERTIES_FORMAT, - obj->id, - obj->x, - obj->y, - obj->colliding, - obj->force, - obj->state - }; - - if (DEBUG & PLAYER_DEBUG) - fprintf(stdout, "PLAYER_DEBUG: player '%d' properties (%d, %d, %d, %d)\n", - obj->id, obj->x, obj->y, obj->colliding, obj->force); - - SDLNet_TCP_Send(socket, reply, sizeof(int)*CLIENT_MESSAGE_LEN); - } -} - -int send_player_connect_event(int object_id) { +int broadcast_event(int format, int object_id) { struct object *obj = objects_map[object_id]; for (int iter = 0; iter < connections_count; iter++) { @@ -82,34 +54,7 @@ int send_player_connect_event(int object_id) { continue; int message[] = { - PLAYER_CONNECT_FORMAT, - obj->id, - obj->x, - obj->y, - obj->colliding, - obj->force, - obj->state - }; - - if (DEBUG & PLAYER_DEBUG) - fprintf(stdout, "PLAYER_DEBUG: new player '%d' has connected to the server\n", obj->id); - - SDLNet_TCP_Send(con->socket, message, sizeof(int)*CLIENT_MESSAGE_LEN); - } - - return 0; -} - -int send_player_disconnect_event(int object_id) { - struct object *obj = objects_map[object_id]; - - for (int iter = 0; iter < connections_count; iter++) { - struct connection *con = connections_map[iter]; - if (con == NULL) - continue; - - int message[] = { - PLAYER_DISCONNECT_FORMAT, + format, obj->id, obj->x, obj->y, @@ -118,9 +63,6 @@ int send_player_disconnect_event(int object_id) { obj->state }; - if (DEBUG & PLAYER_DEBUG) - fprintf(stdout, "PLAYER_DEBUG: player '%d' has disconnected from the server\n", obj->id); - SDLNet_TCP_Send(con->socket, message, sizeof(int)*CLIENT_MESSAGE_LEN); } @@ -143,7 +85,7 @@ int handle_player(void *data) { return -1; } - send_player_connect_event(connection_data->obj_id); + broadcast_event(PLAYER_CONNECT_FORMAT, connection_data->obj_id); for (;;) { char message[SERVER_MESSAGE_LEN]; @@ -170,11 +112,11 @@ int handle_player(void *data) { update_client: handle_player_physics(obj); - send_player_positions(connection_data->socket, connection_data->obj_id); + broadcast_event(OBJECT_PROPERTIES_FORMAT, connection_data->obj_id); } // Communicate client disconnect - send_player_disconnect_event(connection_data->obj_id); + broadcast_event(PLAYER_DISCONNECT_FORMAT, connection_data->obj_id); SDLNet_FreeSocketSet(set); SDLNet_TCP_Close(connection_data->socket); @@ -244,47 +186,28 @@ int main(int argc, char *argv[]) { fprintf(stdout, "Notice: accepted a connection from client!\n"); - int new_object_position = new_key_position((void **) objects_map, objects_count); - if (new_object_position == objects_count) { - objects_map = (struct object **) realloc(objects_map, sizeof(struct object *)*objects_count); - objects_count++; - } - if (objects_map == NULL) { - fprintf(stderr, "Error: failed reallocating objects hash map\n"); - return -1; + int new_object_slot = allocate_value((void ***) &objects_map, &objects_count, sizeof(struct object)); + if (new_object_slot == MEMERR) { + fprintf(stderr, "MEMERR: failed allocating memory for new object\n"); + return STDERR; } - struct object *new_object = (struct object *) calloc(1, sizeof(struct object)); - if (new_object == NULL) { - fprintf(stderr, "Error: failed allocating memory for new object\n"); - return -1; + int new_connection_slot = allocate_value((void ***) &connections_map, &connections_count, sizeof(struct connection)); + if (new_connection_slot == MEMERR) { + fprintf(stderr, "MEMERR: failed allocating memory for new connection\n"); + return STDERR; } - int new_connection_position = new_key_position((void **) connections_map, connections_count); - if (new_connection_position == connections_count) { - connections_map = (struct connection **) realloc(connections_map, sizeof(struct connection *)*connections_count); - connections_count++; - } - if (connections_map == NULL) { - fprintf(stderr, "Error: failed reallocating connections hash map\n"); - return -1; - } + struct object *new_object = objects_map[new_object_slot]; + struct connection *new_connection = connections_map[new_connection_slot]; - struct connection *new_connection = (struct connection *) calloc(1, sizeof(struct connection)); - if (new_connection == NULL) { - fprintf(stderr, "Error: failed allocating memory for new connection object\n"); - return -1; - } - - objects_map[new_object_position] = new_object; - connections_map[new_connection_position] = new_connection; - new_object->id = new_object_position; - new_connection->id = new_connection_position; + new_object->id = new_object_slot; + new_connection->id = new_connection_slot; new_connection->socket = client; - new_connection->obj_id = new_object_position; + new_connection->obj_id = new_object_slot; if (DEBUG & PLAYER_DEBUG) - fprintf(stdout, "Notice: new player object id: %d\n", new_object_position); + fprintf(stdout, "Created connection with id '%d' and object '%d'\n", new_connection->id, new_object->id); SDL_CreateThread(handle_player, "client", new_connection); }