03: refactor the code (client+server)

This commit is contained in:
0xdeadbeer 2023-11-21 00:30:39 +01:00
parent c048742117
commit 4542d4311f
10 changed files with 227 additions and 204 deletions

View File

@ -7,6 +7,11 @@
#define SERVER_ADDR "127.0.0.1" #define SERVER_ADDR "127.0.0.1"
#define SERVER_PORT 9080 #define SERVER_PORT 9080
// ERRORS
#define STDOK 0
#define STDERR -1
#define MEMERR -2
// SDL2 // SDL2
#define SCREEN_WIDTH 1000 #define SCREEN_WIDTH 1000
#define SCREEN_HEIGHT 480 #define SCREEN_HEIGHT 480

View File

@ -0,0 +1,64 @@
#include <SDL2/SDL.h>
#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;
}

View File

@ -0,0 +1,9 @@
#ifndef FORMAT_H
#define FORMAT_H
#include <stdlib.h>
int handle_player_connect(int *message, struct object ***map, int *slots);
int handle_object_properties(int *message, struct object ***map, int *slots);
#endif

View File

@ -4,6 +4,7 @@
#include <SDL2/SDL_net.h> #include <SDL2/SDL_net.h>
#include "structs.h" #include "structs.h"
#include "defs.h" #include "defs.h"
#include "format.h"
#define DEBUG 1 #define DEBUG 1
@ -16,15 +17,12 @@ double last_frame;
// network // network
TCPsocket server_socket; TCPsocket server_socket;
// scene
struct object *player;
// textures // textures
SDL_Texture *idle_animation; SDL_Texture *idle_animation;
SDL_Texture *jump_animation;
SDL_Texture *run_animation; SDL_Texture *run_animation;
SDL_Texture *jump_animation;
// scene
int objects_count = 0; int objects_count = 0;
struct object ** objects_map; struct object ** objects_map;
@ -75,59 +73,6 @@ SDL_Texture *load_texture(const char *path) {
return texture; 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) { void present_scene(void) {
SDL_RenderPresent(game.renderer); SDL_RenderPresent(game.renderer);
} }
@ -168,28 +113,11 @@ int handle_server(void *data) {
if (DEBUG) if (DEBUG)
fprintf(stdout, "DEBUG: PLAYER CONNECT MESSAGE\n"); fprintf(stdout, "DEBUG: PLAYER CONNECT MESSAGE\n");
if (message[1] >= objects_count) { int ret = handle_player_connect(message, &objects_map, &objects_count);
objects_map = (struct object **) realloc(objects_map, sizeof(struct object *)*message[1]); if (ret == MEMERR) {
objects_count = message[1]+1; 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; continue;
} }
@ -197,33 +125,13 @@ int handle_server(void *data) {
if (message[0] == OBJECT_PROPERTIES_FORMAT) { if (message[0] == OBJECT_PROPERTIES_FORMAT) {
if (DEBUG) if (DEBUG)
fprintf(stdout, "DEBUG: OBJECT PROPERTIES MESSAGE FOR ID %d\n", message[1]); fprintf(stdout, "DEBUG: OBJECT PROPERTIES MESSAGE FOR ID %d\n", message[1]);
if (message[1] >= objects_count) { int ret = handle_object_properties(message, &objects_map, &objects_count);
objects_map = (struct object **) realloc(objects_map, sizeof(struct object *)*message[1]); if (ret == MEMERR) {
objects_count = message[1]+1; fprintf(stderr, "MEMERR: Failed handling memory for new object properties\n");
} return MEMERR;
if (objects_map == NULL) {
fprintf(stderr, "Error: failed reallocating objects hash map\n");
return -1;
} }
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; continue;
} }
@ -334,7 +242,7 @@ int main(int argc, char *argv[]) {
if (obj->state & JUMP_MOVEMENT) if (obj->state & JUMP_MOVEMENT)
switch_animation(obj, jump_animation); switch_animation(obj, jump_animation);
draw_object(obj); draw_object(&game, obj);
} }
present_scene(); present_scene();

View File

@ -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;
}

View File

@ -22,8 +22,8 @@ struct animation {
struct object { struct object {
SDL_Texture *texture; SDL_Texture *texture;
int resolution; // of the texture/every tile int resolution; // of the texture/every tile
int id; int id;
int x; int x;
int y; int y;
int scale; int scale;
@ -40,4 +40,8 @@ struct object {
int force; 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 #endif

View File

@ -5,6 +5,10 @@
#define GENERAL_DEBUG 0x0001 #define GENERAL_DEBUG 0x0001
#define PLAYER_DEBUG 0x0010 #define PLAYER_DEBUG 0x0010
// ERRORS
#define STDERR -1
#define MEMERR -2
// MCS: Message Communication Standard // MCS: Message Communication Standard
#define SERVER_MESSAGE_LEN 10 #define SERVER_MESSAGE_LEN 10
#define CLIENT_MESSAGE_LEN 7 #define CLIENT_MESSAGE_LEN 7

View File

@ -0,0 +1,43 @@
#include <stdio.h>
#include <stdlib.h>
#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;
}

View File

@ -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

View File

@ -4,8 +4,9 @@
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <SDL2/SDL_net.h> #include <SDL2/SDL_net.h>
#include <SDL2/SDL_error.h> #include <SDL2/SDL_error.h>
#include "structs.h"
#include "defs.h" #include "defs.h"
#include "structs.h"
#include "hashmap.h"
#define DEBUG 0x0010 #define DEBUG 0x0010
#define PORT 9080 #define PORT 9080
@ -44,36 +45,7 @@ void handle_player_physics(struct object *obj) {
obj->y += obj->force; obj->y += obj->force;
} }
void send_player_positions(TCPsocket socket, int player_id) { int broadcast_event(int format, int object_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) {
struct object *obj = objects_map[object_id]; struct object *obj = objects_map[object_id];
for (int iter = 0; iter < connections_count; iter++) { for (int iter = 0; iter < connections_count; iter++) {
@ -82,34 +54,7 @@ int send_player_connect_event(int object_id) {
continue; continue;
int message[] = { int message[] = {
PLAYER_CONNECT_FORMAT, 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,
obj->id, obj->id,
obj->x, obj->x,
obj->y, obj->y,
@ -118,9 +63,6 @@ int send_player_disconnect_event(int object_id) {
obj->state 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); SDLNet_TCP_Send(con->socket, message, sizeof(int)*CLIENT_MESSAGE_LEN);
} }
@ -143,7 +85,7 @@ int handle_player(void *data) {
return -1; return -1;
} }
send_player_connect_event(connection_data->obj_id); broadcast_event(PLAYER_CONNECT_FORMAT, connection_data->obj_id);
for (;;) { for (;;) {
char message[SERVER_MESSAGE_LEN]; char message[SERVER_MESSAGE_LEN];
@ -170,11 +112,11 @@ int handle_player(void *data) {
update_client: update_client:
handle_player_physics(obj); 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 // Communicate client disconnect
send_player_disconnect_event(connection_data->obj_id); broadcast_event(PLAYER_DISCONNECT_FORMAT, connection_data->obj_id);
SDLNet_FreeSocketSet(set); SDLNet_FreeSocketSet(set);
SDLNet_TCP_Close(connection_data->socket); 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"); fprintf(stdout, "Notice: accepted a connection from client!\n");
int new_object_position = new_key_position((void **) objects_map, objects_count); int new_object_slot = allocate_value((void ***) &objects_map, &objects_count, sizeof(struct object));
if (new_object_position == objects_count) { if (new_object_slot == MEMERR) {
objects_map = (struct object **) realloc(objects_map, sizeof(struct object *)*objects_count); fprintf(stderr, "MEMERR: failed allocating memory for new object\n");
objects_count++; return STDERR;
}
if (objects_map == NULL) {
fprintf(stderr, "Error: failed reallocating objects hash map\n");
return -1;
} }
struct object *new_object = (struct object *) calloc(1, sizeof(struct object)); int new_connection_slot = allocate_value((void ***) &connections_map, &connections_count, sizeof(struct connection));
if (new_object == NULL) { if (new_connection_slot == MEMERR) {
fprintf(stderr, "Error: failed allocating memory for new object\n"); fprintf(stderr, "MEMERR: failed allocating memory for new connection\n");
return -1; return STDERR;
} }
int new_connection_position = new_key_position((void **) connections_map, connections_count); struct object *new_object = objects_map[new_object_slot];
if (new_connection_position == connections_count) { struct connection *new_connection = connections_map[new_connection_slot];
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 connection *new_connection = (struct connection *) calloc(1, sizeof(struct connection)); new_object->id = new_object_slot;
if (new_connection == NULL) { new_connection->id = new_connection_slot;
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_connection->socket = client; new_connection->socket = client;
new_connection->obj_id = new_object_position; new_connection->obj_id = new_object_slot;
if (DEBUG & PLAYER_DEBUG) 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); SDL_CreateThread(handle_player, "client", new_connection);
} }