diff --git a/04-collision/.imgs/showcase.png b/04-collision/.imgs/showcase.png new file mode 100644 index 0000000..bbb63ef Binary files /dev/null and b/04-collision/.imgs/showcase.png differ diff --git a/04-collision/client/Makefile b/04-collision/client/Makefile new file mode 100644 index 0000000..5545841 --- /dev/null +++ b/04-collision/client/Makefile @@ -0,0 +1,28 @@ +CC=gcc +CFLAGS=`pkg-config --cflags sdl2 SDL2_image SDL2_net` +LDFLAGS=`pkg-config --libs sdl2 SDL2_image SDL2_net` +TARGET=client +SDIR=src +ADIR=assets +ODIR=build + +SRC=$(shell find $(SDIR) -type f -name *.c) +OBJ=$(SRC:.c=.o) + +all: $(TARGET) + +.PHONY: default +$(TARGET): $(OBJ) + mkdir -p build + cp -rf $(ADIR) $(ODIR)/$(ADIR) + $(CC) -o $(ODIR)/$@ $^ $(LDFLAGS) + +%.o: %.c + $(CC) $(CFLAGS) -o $@ -c $< + +run: + $(ODIR)/$(TARGET) + +.PHONY: clean +clean: + rm -f $(ODIR)/$(TARGET) $(OBJ) diff --git a/04-collision/client/README.md b/04-collision/client/README.md new file mode 100644 index 0000000..07cdb1d --- /dev/null +++ b/04-collision/client/README.md @@ -0,0 +1,3 @@ +# Collision - Client + +Client-side code for 04-collision diff --git a/04-collision/client/assets/player/idle_down.png b/04-collision/client/assets/player/idle_down.png new file mode 100644 index 0000000..3241ca6 Binary files /dev/null and b/04-collision/client/assets/player/idle_down.png differ diff --git a/04-collision/client/assets/player/idle_left.png b/04-collision/client/assets/player/idle_left.png new file mode 100644 index 0000000..9f5e370 Binary files /dev/null and b/04-collision/client/assets/player/idle_left.png differ diff --git a/04-collision/client/assets/player/idle_right.png b/04-collision/client/assets/player/idle_right.png new file mode 100644 index 0000000..66a019b Binary files /dev/null and b/04-collision/client/assets/player/idle_right.png differ diff --git a/04-collision/client/assets/player/idle_up.png b/04-collision/client/assets/player/idle_up.png new file mode 100644 index 0000000..8c3fd06 Binary files /dev/null and b/04-collision/client/assets/player/idle_up.png differ diff --git a/04-collision/client/assets/player/move_down.png b/04-collision/client/assets/player/move_down.png new file mode 100644 index 0000000..6d6e1e9 Binary files /dev/null and b/04-collision/client/assets/player/move_down.png differ diff --git a/04-collision/client/assets/player/move_left.png b/04-collision/client/assets/player/move_left.png new file mode 100644 index 0000000..9565034 Binary files /dev/null and b/04-collision/client/assets/player/move_left.png differ diff --git a/04-collision/client/assets/player/move_right.png b/04-collision/client/assets/player/move_right.png new file mode 100644 index 0000000..4c49d51 Binary files /dev/null and b/04-collision/client/assets/player/move_right.png differ diff --git a/04-collision/client/assets/player/move_up.png b/04-collision/client/assets/player/move_up.png new file mode 100644 index 0000000..f702e80 Binary files /dev/null and b/04-collision/client/assets/player/move_up.png differ diff --git a/04-collision/client/assets/player/tilemap.png b/04-collision/client/assets/player/tilemap.png new file mode 100644 index 0000000..1f5af92 Binary files /dev/null and b/04-collision/client/assets/player/tilemap.png differ diff --git a/04-collision/client/src/defs.h b/04-collision/client/src/defs.h new file mode 100644 index 0000000..df4f058 --- /dev/null +++ b/04-collision/client/src/defs.h @@ -0,0 +1,37 @@ +#ifndef DEFS_H +#define DEFS_H + +#include + +// Server details +#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 +#define WINDOW_FLAGS SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL +#define RENDERER_FLAGS SDL_RENDERER_ACCELERATED + +// MCS: Message Communication Standard +#define SERVER_MESSAGE_LEN 10 +#define CLIENT_MESSAGE_LEN 7 + +// MFS: Message Format Standard +#define PLAYER_CONNECT_FORMAT 0 +#define OBJECT_PROPERTIES_FORMAT 1 +#define PLAYER_DISCONNECT_FORMAT 2 + +// MSCA: Message Communication Standard Actions +#define LEFT_MOVEMENT 0b10000000 +#define RIGHT_MOVEMENT 0b01000000 +#define UP_MOVEMENT 0b00100000 +#define DOWN_MOVEMENT 0b00010000 +#define NO_MOVEMENT 0b00000000 + +#endif diff --git a/04-collision/client/src/format.c b/04-collision/client/src/format.c new file mode 100644 index 0000000..afbe628 --- /dev/null +++ b/04-collision/client/src/format.c @@ -0,0 +1,62 @@ +#include +#include "defs.h" +#include "structs.h" +#include "format.h" + +extern SDL_Texture *idle_down_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_down_animation, 4, 64); + 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_down_animation, 4, 64); + 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/04-collision/client/src/format.h b/04-collision/client/src/format.h new file mode 100644 index 0000000..f84065a --- /dev/null +++ b/04-collision/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/04-collision/client/src/main.c b/04-collision/client/src/main.c new file mode 100644 index 0000000..9914a22 --- /dev/null +++ b/04-collision/client/src/main.c @@ -0,0 +1,278 @@ +#include +#include +#include +#include +#include "structs.h" +#include "defs.h" +#include "format.h" + +#define DEBUG 1 + +int game_running = 1; +struct game game; +int movement_speed = 10; +double delta_time; +double last_frame; + +// network +TCPsocket server_socket; + +// textures +SDL_Texture *idle_animation; +SDL_Texture *move_left_animation; +SDL_Texture *move_right_animation; +SDL_Texture *move_up_animation; +SDL_Texture *move_down_animation; +SDL_Texture *idle_left_animation; +SDL_Texture *idle_right_animation; +SDL_Texture *idle_up_animation; +SDL_Texture *idle_down_animation; + +// scene +int objects_count = 0; +struct object ** objects_map; + +void prepare_scene(void) { + SDL_SetRenderDrawColor(game.renderer, 96, 128, 255, 255); + SDL_RenderClear(game.renderer); +} + +void key(SDL_KeyboardEvent *event) { + if (event->repeat != 0) + return; + + if (event->keysym.scancode == SDL_SCANCODE_D) + game.left = !game.left; + if (event->keysym.scancode == SDL_SCANCODE_F) + game.right = !game.right; + if (event->keysym.scancode == SDL_SCANCODE_K) + game.up = !game.up; + if (event->keysym.scancode == SDL_SCANCODE_J) + game.down = !game.down; +} + +void handle_input(void) { + SDL_Event event; + + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + game_running = 0; + break; + case SDL_KEYDOWN: + case SDL_KEYUP: + key(&event.key); + break; + default: + break; + } + if (event.type == SDL_QUIT) + game_running = 0; + } +} + +SDL_Texture *load_texture(const char *path) { + SDL_Texture *texture; + + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Loading %s", path); + + texture = IMG_LoadTexture(game.renderer, path); + + return texture; +} + +void present_scene(void) { + SDL_RenderPresent(game.renderer); +} + +int new_key_position(void **map, int slots) { + int slot = 0; + + if (slots <= 0) + return slot; + + if (map == NULL) + return slot; + + while (slot <= slots) { + if (map[slots] == NULL) + break; + + slot++; + } + + return slot; +} + +int handle_server(void *data) { + for (;;) { + int message[CLIENT_MESSAGE_LEN]; + int recv_len = SDLNet_TCP_Recv(server_socket, message, sizeof(int)*CLIENT_MESSAGE_LEN); + + if (!recv_len) { + fprintf(stderr, "Error: failed receiving message from server\n%s\n", SDLNet_GetError()); + break; + } + + if (DEBUG) + fprintf(stdout, "Notice: received '%d' bytes from server\n", recv_len); + + if (message[0] == PLAYER_CONNECT_FORMAT) { + if (DEBUG) + fprintf(stdout, "DEBUG: PLAYER CONNECT MESSAGE\n"); + + 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; + } + + continue; + } + + if (message[0] == OBJECT_PROPERTIES_FORMAT) { + if (DEBUG) + fprintf(stdout, "DEBUG: OBJECT PROPERTIES MESSAGE FOR ID %d\n", message[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; + } + + continue; + } + + if (message[0] == PLAYER_DISCONNECT_FORMAT) { + if (DEBUG) + fprintf(stdout, "DEBUG: PLAYER DISCONNECT MESSAGE\n"); + + int object_id = message[1]; + + free(objects_map[object_id]); + objects_map[object_id] = NULL; + + continue; + } + } + + return 0; +} + +int connect_to_server(void) { + IPaddress ip; + if (SDLNet_ResolveHost(&ip, SERVER_ADDR, SERVER_PORT) != 0) { + fprintf(stderr, "Error: resolving host of server\n%s\n", SDLNet_GetError()); + return -1; + } + + server_socket = SDLNet_TCP_Open(&ip); + if (!server_socket) { + fprintf(stderr, "Error: failed opening socket to '%s' at '%d'\n%s\n", SERVER_ADDR, SERVER_PORT, SDLNet_GetError()); + return -1; + } + + SDL_CreateThread(handle_server, "server", NULL); + + return 0; +} + +int main(int argc, char *argv[]) { + if (SDL_Init(SDL_INIT_VIDEO) != 0) { + fprintf(stderr, "Error: could not initialize SDL\n%s\n", SDL_GetError()); + return -1; + } + + if (SDLNet_Init() != 0) { + fprintf(stderr, "Error: could not initialize SDL net\n%s\n", SDL_GetError()); + return -1; + } + + game.window = SDL_CreateWindow("03-network", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, WINDOW_FLAGS); + + if (game.window == NULL) { + fprintf(stderr, "Error: could not create window\n%s\n", SDL_GetError()); + return -1; + } + + game.renderer = SDL_CreateRenderer(game.window, -1, RENDERER_FLAGS); + + if (game.renderer == NULL) { + fprintf(stderr, "Error: could not create renderer\n%s\n", SDL_GetError()); + return -1; + } + + // load player animations + move_left_animation = load_texture("assets/player/move_left.png"); + move_right_animation = load_texture("assets/player/move_right.png"); + move_up_animation = load_texture("assets/player/move_up.png"); + move_down_animation = load_texture("assets/player/move_down.png"); + idle_left_animation = load_texture("assets/player/idle_left.png"); + idle_right_animation = load_texture("assets/player/idle_right.png"); + idle_up_animation = load_texture("assets/player/idle_up.png"); + idle_down_animation = load_texture("assets/player/idle_down.png"); + idle_animation = idle_down_animation; + + if (connect_to_server() != 0) + return -1; + + // game loop + while (game_running) { + double current_frame = SDL_GetTicks(); + delta_time = current_frame - last_frame; + last_frame = current_frame; + + prepare_scene(); + handle_input(); + + uint8_t message[SERVER_MESSAGE_LEN]; + message[0] = (game.left << 7) | + (game.right << 6) | + (game.up << 5) | + (game.down << 4); + + SDLNet_TCP_Send(server_socket, message, sizeof(uint8_t)*SERVER_MESSAGE_LEN); + + for (int iter = 0; iter < objects_count; iter++) { + struct object *obj = objects_map[iter]; + if (obj == NULL) + continue; + + if (obj->state & LEFT_MOVEMENT) { + switch_animation(obj, move_left_animation); + idle_animation = idle_left_animation; + } + + if (obj->state & RIGHT_MOVEMENT) { + switch_animation(obj, move_right_animation); + idle_animation = idle_right_animation; + } + + if (obj->state & UP_MOVEMENT) { + switch_animation(obj, move_up_animation); + idle_animation = idle_up_animation; + } + + if (obj->state & DOWN_MOVEMENT) { + switch_animation(obj, move_down_animation); + idle_animation = idle_down_animation; + } + + if (obj->state == NO_MOVEMENT) + switch_animation(obj, idle_animation); + + obj->animation_speed = 6; + + draw_object(&game, obj); + } + + present_scene(); + + SDL_Delay(16); + } + + SDL_DestroyWindow(game.window); + SDL_Quit(); + + return 0; +} diff --git a/04-collision/client/src/object.c b/04-collision/client/src/object.c new file mode 100644 index 0000000..6be16b5 --- /dev/null +++ b/04-collision/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/04-collision/client/src/structs.h b/04-collision/client/src/structs.h new file mode 100644 index 0000000..fa37e25 --- /dev/null +++ b/04-collision/client/src/structs.h @@ -0,0 +1,48 @@ +#ifndef STRUCTS_H +#define STRUCTS_H + +#include + +struct game { + SDL_Window *window; + SDL_Renderer *renderer; + + int left; + int right; + int up; + int down; +}; + +struct animation { + SDL_Texture *tilemap; + int resolution; + + int skippable; +}; + +struct object { + SDL_Texture *texture; + int resolution; // of the texture/every tile + int id; + + int x; + int y; + int scale; + Uint32 flip; + + // animation + double animation_clock; // everytime it reaches 1, the texture switches to the next slide + double animation_speed; // how fast will the clock reach 1 with respect to delta_time + int animation_slide; // the current slide of the animation + + uint8_t state; + + int colliding; + 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/04-collision/server/Makefile b/04-collision/server/Makefile new file mode 100644 index 0000000..a606484 --- /dev/null +++ b/04-collision/server/Makefile @@ -0,0 +1,28 @@ +CC=gcc +CFLAGS=`pkg-config --cflags sdl2 SDL2_net` +LDFLAGS=`pkg-config --libs sdl2 SDL2_net` +TARGET=server +SDIR=src +ADIR=assets +ODIR=build + +SRC=$(shell find $(SDIR) -type f -name *.c) +OBJ=$(SRC:.c=.o) + +all: $(TARGET) + +.PHONY: default +$(TARGET): $(OBJ) + mkdir -p build + cp -rf $(ADIR) $(ODIR)/$(ADIR) + $(CC) -o $(ODIR)/$@ $^ $(LDFLAGS) + +%.o: %.c + $(CC) $(CFLAGS) -o $@ -c $< + +run: + $(ODIR)/$(TARGET) + +.PHONY: clean +clean: + rm -f $(ODIR)/$(TARGET) $(OBJ) diff --git a/04-collision/server/README.md b/04-collision/server/README.md new file mode 100644 index 0000000..c3ea17a --- /dev/null +++ b/04-collision/server/README.md @@ -0,0 +1,3 @@ +# Collision - Server + +Server-side code for 04-collision diff --git a/04-collision/server/src/defs.h b/04-collision/server/src/defs.h new file mode 100644 index 0000000..3294e62 --- /dev/null +++ b/04-collision/server/src/defs.h @@ -0,0 +1,31 @@ +#ifndef DEFS_H +#define DEFS_H + +// DEBUG +#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 + +// MFS: Message Format Standard +#define PLAYER_CONNECT_FORMAT 0 +#define OBJECT_PROPERTIES_FORMAT 1 +#define PLAYER_DISCONNECT_FORMAT 2 + +// MCSA: Message Communication Standard Actions +#define LEFT_MOVEMENT 0b10000000 +#define RIGHT_MOVEMENT 0b01000000 +#define UP_MOVEMENT 0b00100000 +#define DOWN_MOVEMENT 0b00010000 + +// OC: Object Constants +#define GRAVITY 2 +#define MOVEMENT_SPEED 10 + +#endif diff --git a/04-collision/server/src/main.c b/04-collision/server/src/main.c new file mode 100644 index 0000000..531f7f8 --- /dev/null +++ b/04-collision/server/src/main.c @@ -0,0 +1,216 @@ +#include +#include +#include +#include +#include +#include +#include "defs.h" +#include "structs.h" +#include "structures.h" + +#define DEBUG 0x0010 +#define PORT 9080 + +struct object **objects_map; +int objects_map_size = 0; +int objects_count = 0; + +struct connection **connections_map; +int connections_map_size = 0; +int connections_count = 0; + +void handle_player_input(struct object *obj, char *message) { + uint8_t action = message[0]; + + if (action & LEFT_MOVEMENT) + obj->x -= MOVEMENT_SPEED; + + if (action & RIGHT_MOVEMENT) + obj->x += MOVEMENT_SPEED; + + if (action & UP_MOVEMENT) + obj->y -= MOVEMENT_SPEED; + + if (action & DOWN_MOVEMENT) + obj->y += MOVEMENT_SPEED; + + obj->state = action; +} + +void handle_player_physics(struct object *obj) { +} + +int broadcast_event(int format, int object_id) { + struct object *obj = objects_map[object_id]; + + for (int iter = 0; iter < connections_map_size; iter++) { + struct connection *con = connections_map[iter]; + if (con == NULL) + continue; + + int message[] = { + format, + obj->id, + obj->x, + obj->y, + obj->colliding, + obj->force, + obj->state + }; + + SDLNet_TCP_Send(con->socket, message, sizeof(int)*CLIENT_MESSAGE_LEN); + } + + return 0; +} + +int handle_player(void *data) { + struct connection *connection_data = (struct connection *) data; + struct object *obj = objects_map[connection_data->obj_id]; + + SDLNet_SocketSet set = SDLNet_AllocSocketSet(1); + if (set == NULL) { + fprintf(stderr, "Error: cannot allocate memory for a new socket set\n"); + return -1; + } + + int ret = SDLNet_TCP_AddSocket(set, connection_data->socket); + if (ret == -1) { + fprintf(stderr, "Error: max socket count in socket set reached\n"); + return -1; + } + + broadcast_event(PLAYER_CONNECT_FORMAT, connection_data->obj_id); + + for (;;) { + char message[SERVER_MESSAGE_LEN]; + int ready_sockets = SDLNet_CheckSockets(set, 100); + if (ready_sockets == -1) { + fprintf(stderr, "Error: cannot call select() system call with SDLNet_CheckSockets()\n"); + continue; + } + + if (ready_sockets == 0) + goto update_client; + + int recv_len = SDLNet_TCP_Recv(connection_data->socket, message, SERVER_MESSAGE_LEN); + if (!recv_len) { + // player disconnected + fprintf(stderr, "Error: failed receiving message\n%s\n", SDLNet_GetError()); + break; + } + + if (DEBUG & GENERAL_DEBUG) + fprintf(stdout, "Notice: received '%s' and '%d' bytes\n", message, recv_len); + + handle_player_input(obj, message); + + update_client: + handle_player_physics(obj); + broadcast_event(OBJECT_PROPERTIES_FORMAT, connection_data->obj_id); + } + + // Communicate client disconnect + broadcast_event(PLAYER_DISCONNECT_FORMAT, connection_data->obj_id); + + SDLNet_FreeSocketSet(set); + SDLNet_TCP_Close(connection_data->socket); + + objects_map[connection_data->obj_id] = NULL; + objects_count--; + + connections_map[connection_data->id] = NULL; + connections_count--; + + free(obj); + free(data); + + return 0; +} + +void catch_alarm(int sig) { + fprintf(stdout, "Notice: force stopping server...\n"); + exit(EXIT_SUCCESS); +} + +int new_key_position(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 main(int argc, char *argv[]) { + signal(SIGINT, catch_alarm); + + if (SDL_Init(SDL_INIT_VIDEO) != 0) { + fprintf(stderr, "Error: could not initialize SDL\n%s\n", SDL_GetError()); + return -1; + } + + if (SDLNet_Init() != 0) { + fprintf(stderr, "Error: could not initialize SDL net\n%s\n", SDL_GetError()); + return -1; + } + + IPaddress ip; + if (SDLNet_ResolveHost(&ip, NULL, PORT) == -1) { + fprintf(stderr, "Error: failed resolving host \n%s\n", SDL_GetError()); + return -1; + } + + TCPsocket server = SDLNet_TCP_Open(&ip); + if (!server) { + fprintf(stderr, "Error: failed opening socket at %d\n%s\n", PORT, SDL_GetError()); + return -1; + } + + for (;;) { + TCPsocket client = SDLNet_TCP_Accept(server); + if (!client) { + SDL_Delay(100); + continue; + } + + fprintf(stdout, "Notice: accepted a connection from client!\n"); + + int new_object_slot = map_allocate_value((void ***) &objects_map, &objects_map_size, &objects_count, sizeof(struct object)); + if (new_object_slot == MEMERR) { + fprintf(stderr, "MEMERR: failed allocating memory for new object\n"); + return STDERR; + } + + int new_connection_slot = map_allocate_value((void ***) &connections_map, &connections_map_size, &connections_count, sizeof(struct connection)); + if (new_connection_slot == MEMERR) { + fprintf(stderr, "MEMERR: failed allocating memory for new connection\n"); + return STDERR; + } + + struct object *new_object = objects_map[new_object_slot]; + struct connection *new_connection = connections_map[new_connection_slot]; + + new_object->id = new_object_slot; + new_connection->id = new_connection_slot; + new_connection->socket = client; + new_connection->obj_id = new_object_slot; + + if (DEBUG & PLAYER_DEBUG) + fprintf(stdout, "Created connection with id '%d' and object '%d'\n", new_connection->id, new_object->id); + + SDL_CreateThread(handle_player, "client", new_connection); + } + + return 0; +} diff --git a/04-collision/server/src/structs.h b/04-collision/server/src/structs.h new file mode 100644 index 0000000..aeb32d0 --- /dev/null +++ b/04-collision/server/src/structs.h @@ -0,0 +1,23 @@ +#ifndef STRUCTS_H +#define STRUCTS_H + +#include + +struct connection { + int id; + int obj_id; + TCPsocket socket; +}; + +struct object { + int id; + int x; + int y; + + int colliding; + int force; + + uint8_t state; +}; + +#endif diff --git a/04-collision/server/src/structures.c b/04-collision/server/src/structures.c new file mode 100644 index 0000000..60e0cf7 --- /dev/null +++ b/04-collision/server/src/structures.c @@ -0,0 +1,55 @@ +#include +#include +#include "structures.h" +#include "defs.h" + +int map_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; +} + +// If there's Nx fewer used slots than total slots in the map, find the first possible one. +// Else reallocate the map and use the end slot +// Then allocate an object of size BYTES and add it into the map. +int map_allocate_value(void ***map, int *total_slots, int *used_slots, int bytes) { + int half_slots = (*total_slots) / 2; + int empty_slot = 0; + + if (*used_slots < half_slots) { + empty_slot = map_find_empty_slot(*map, *used_slots); + goto jump; + } + + empty_slot = *total_slots; + (*total_slots)++; + *map = realloc(*map, sizeof(void *)*(*total_slots)); + +jump: + if (*map == NULL) + return MEMERR; + + void *new_value = calloc(1, bytes); + if (new_value == NULL) + return MEMERR; + + (*used_slots)++; + (*map)[empty_slot] = new_value; + + return empty_slot; +} + + diff --git a/04-collision/server/src/structures.h b/04-collision/server/src/structures.h new file mode 100644 index 0000000..d216630 --- /dev/null +++ b/04-collision/server/src/structures.h @@ -0,0 +1,9 @@ +#ifndef STRUCTURES_H +#define STRUCTURES_H + +#include "structs.h" + +int map_find_empty_slot(void **map, int slots); +int map_allocate_value(void ***map, int *total_slots, int *used_slots, int bytes); + +#endif