03: show other players in game as well

Will refactor in the future.
This was just a PoC
This commit is contained in:
0xdeadbeer 2023-11-20 00:14:17 +01:00
parent 51177e3a19
commit c048742117
6 changed files with 357 additions and 116 deletions

View File

@ -0,0 +1,31 @@
#ifndef DEFS_H
#define DEFS_H
#include <SDL2/SDL.h>
// Server details
#define SERVER_ADDR "127.0.0.1"
#define SERVER_PORT 9080
// 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 JUMP_MOVEMENT 0b00100000
#define CROUCH_MOVEMENT 0b00010000
#endif

View File

@ -3,18 +3,11 @@
#include <SDL2/SDL_image.h> #include <SDL2/SDL_image.h>
#include <SDL2/SDL_net.h> #include <SDL2/SDL_net.h>
#include "structs.h" #include "structs.h"
#include "defs.h"
#define DEBUG 1 #define DEBUG 1
#define SERVER_ADDR "127.0.0.1"
#define SERVER_PORT 9080
#define SERVER_MESSAGE_LEN 10 // 0-1 BYTE: Action details, 2-9: Other data (not sure we even need this)
#define CLIENT_MESSAGE_LEN 4 // 4 PROPERTIES (each of 4 BYTES)
const int SCREEN_WIDTH = 1000; int game_running = 1;
const int SCREEN_HEIGHT = 480;
const Uint32 WINDOW_FLAGS = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL;
const Uint32 RENDERER_FLAGS = SDL_RENDERER_ACCELERATED;
int GAME_RUNNING = 1;
struct game game; struct game game;
int movement_speed = 10; int movement_speed = 10;
double delta_time; double delta_time;
@ -26,6 +19,15 @@ TCPsocket server_socket;
// scene // scene
struct object *player; struct object *player;
// textures
SDL_Texture *idle_animation;
SDL_Texture *jump_animation;
SDL_Texture *run_animation;
int objects_count = 0;
struct object ** objects_map;
void prepare_scene(void) { void prepare_scene(void) {
SDL_SetRenderDrawColor(game.renderer, 96, 128, 255, 255); SDL_SetRenderDrawColor(game.renderer, 96, 128, 255, 255);
SDL_RenderClear(game.renderer); SDL_RenderClear(game.renderer);
@ -49,7 +51,7 @@ void handle_input(void) {
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
switch (event.type) { switch (event.type) {
case SDL_QUIT: case SDL_QUIT:
GAME_RUNNING = 0; game_running = 0;
break; break;
case SDL_KEYDOWN: case SDL_KEYDOWN:
case SDL_KEYUP: case SDL_KEYUP:
@ -58,9 +60,8 @@ void handle_input(void) {
default: default:
break; break;
} }
if (event.type == SDL_QUIT) { if (event.type == SDL_QUIT)
GAME_RUNNING = 0; game_running = 0;
}
} }
} }
@ -131,6 +132,25 @@ void present_scene(void) {
SDL_RenderPresent(game.renderer); 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) { int handle_server(void *data) {
for (;;) { for (;;) {
int message[CLIENT_MESSAGE_LEN]; int message[CLIENT_MESSAGE_LEN];
@ -144,10 +164,80 @@ int handle_server(void *data) {
if (DEBUG) if (DEBUG)
fprintf(stdout, "Notice: received '%d' bytes from server\n", recv_len); fprintf(stdout, "Notice: received '%d' bytes from server\n", recv_len);
player->x = message[0]; if (message[0] == PLAYER_CONNECT_FORMAT) {
player->y = message[1]; if (DEBUG)
player->colliding = message[2]; fprintf(stdout, "DEBUG: PLAYER CONNECT MESSAGE\n");
player->force = message[3];
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;
}
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;
}
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;
}
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;
}
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; return 0;
@ -197,17 +287,15 @@ int main(int argc, char *argv[]) {
} }
// load player animations // load player animations
SDL_Texture *idle_animation = load_texture("assets/player/idle.png"); idle_animation = load_texture("assets/player/idle.png");
SDL_Texture *jump_animation = load_texture("assets/player/jump.png"); jump_animation = load_texture("assets/player/jump.png");
SDL_Texture *run_animation = load_texture("assets/player/run.png"); run_animation = load_texture("assets/player/run.png");
player = create_object(idle_animation, 4, 48);
if (connect_to_server() != 0) if (connect_to_server() != 0)
return -1; return -1;
// game loop // game loop
while (GAME_RUNNING) { while (game_running) {
double current_frame = SDL_GetTicks(); double current_frame = SDL_GetTicks();
delta_time = current_frame - last_frame; delta_time = current_frame - last_frame;
last_frame = current_frame; last_frame = current_frame;
@ -215,42 +303,39 @@ int main(int argc, char *argv[]) {
prepare_scene(); prepare_scene();
handle_input(); handle_input();
uint8_t message[SERVER_MESSAGE_LEN];
message[0] = (game.left << 7) |
(game.right << 6) |
(game.jump << 5);
SDLNet_TCP_Send(server_socket, message, sizeof(uint8_t)*SERVER_MESSAGE_LEN);
// The reason why I don't do // The reason why I don't do
// that much game development // that much game development
// in my free time. Damn youuu ifs // in my free time. Damn youuu ifs
if (player->colliding) { for (int iter = 0; iter < objects_count; iter++) {
if (game.left) struct object *obj = objects_map[iter];
switch_animation(player, run_animation); if (obj == NULL)
if (game.right) continue;
switch_animation(player, run_animation);
if (!game.left && !game.right)
switch_animation(player, idle_animation);
if (game.jump) {
switch_animation(player, jump_animation);
uint8_t message[SERVER_MESSAGE_LEN]; if (obj->state & LEFT_MOVEMENT) {
message[0] = 2; switch_animation(obj, run_animation);
obj->flip = SDL_FLIP_HORIZONTAL;
SDLNet_TCP_Send(server_socket, message, sizeof(uint8_t)*SERVER_MESSAGE_LEN);
}
} }
if (game.left) { if (obj->state & RIGHT_MOVEMENT) {
player->flip = SDL_FLIP_HORIZONTAL; switch_animation(obj, run_animation);
uint8_t message[SERVER_MESSAGE_LEN]; obj->flip = SDL_FLIP_NONE;
message[0] = 1;
SDLNet_TCP_Send(server_socket, message, sizeof(uint8_t)*SERVER_MESSAGE_LEN);
}
if (game.right) {
player->flip = SDL_FLIP_NONE;
uint8_t message[SERVER_MESSAGE_LEN];
message[0] = 0;
SDLNet_TCP_Send(server_socket, message, sizeof(uint8_t)*SERVER_MESSAGE_LEN);
} }
draw_object(player); if (!(obj->state & LEFT_MOVEMENT) && !(obj->state & RIGHT_MOVEMENT))
switch_animation(obj, idle_animation);
if (obj->state & JUMP_MOVEMENT)
switch_animation(obj, jump_animation);
draw_object(obj);
}
present_scene(); present_scene();

View File

@ -23,6 +23,7 @@ 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 x; int x;
int y; int y;
int scale; int scale;
@ -33,6 +34,8 @@ struct object {
double animation_speed; // how fast will the clock reach 1 with respect to delta_time double animation_speed; // how fast will the clock reach 1 with respect to delta_time
int animation_slide; // the current slide of the animation int animation_slide; // the current slide of the animation
uint8_t state;
int colliding; int colliding;
int force; int force;
}; };

View File

@ -1,17 +1,24 @@
#ifndef DEFS_H #ifndef DEFS_H
#define DEFS_H #define DEFS_H
#include <SDL2/SDL.h> // DEBUG
#define GENERAL_DEBUG 0x0001
#define PLAYER_DEBUG 0x0010
// MCS: Message Communication Standard // MCS: Message Communication Standard
#define SERVER_MESSAGE_LEN 10 #define SERVER_MESSAGE_LEN 10
#define CLIENT_MESSAGE_LEN 4 #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 // MCSA: Message Communication Standard Actions
#define RIGHT_MOVEMENT 0 #define LEFT_MOVEMENT 0b10000000
#define LEFT_MOVEMENT 1 #define RIGHT_MOVEMENT 0b01000000
#define JUMP_MOVEMENT 2 #define JUMP_MOVEMENT 0b00100000
#define CROUCH_MOVEMENT 3 #define CROUCH_MOVEMENT 0b00010000
// OC: Object Constants // OC: Object Constants
#define GRAVITY 2 #define GRAVITY 2

View File

@ -7,18 +7,130 @@
#include "structs.h" #include "structs.h"
#include "defs.h" #include "defs.h"
#define DEBUG 0x0010
#define PORT 9080 #define PORT 9080
#define DEBUG 1
int objects_count = 0; int objects_count = 0;
struct object **objects_map; struct object **objects_map;
int connections_count = 0;
struct connection **connections_map;
void handle_player_input(struct object *obj, char *message) {
uint8_t action = message[0];
if (action & RIGHT_MOVEMENT)
obj->x += MOVEMENT_SPEED;
if (action & LEFT_MOVEMENT)
obj->x -= MOVEMENT_SPEED;
if (action & JUMP_MOVEMENT) {
obj->force -= MOVEMENT_SPEED;
obj->colliding = 0;
}
obj->state = action;
}
void handle_player_physics(struct object *obj) {
if (obj->y < 200)
obj->force += GRAVITY;
else {
obj->colliding = 1;
obj->y = 200;
}
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) {
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_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,
obj->id,
obj->x,
obj->y,
obj->colliding,
obj->force,
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);
}
return 0;
}
int handle_player(void *data) { int handle_player(void *data) {
struct connection *connection_data = (struct connection *) data; struct connection *connection_data = (struct connection *) data;
struct object *obj = objects_map[connection_data->obj_id]; struct object *obj = objects_map[connection_data->obj_id];
memset(obj, 0, sizeof(struct object));
SDLNet_SocketSet set = SDLNet_AllocSocketSet(1); SDLNet_SocketSet set = SDLNet_AllocSocketSet(1);
if (set == NULL) { if (set == NULL) {
fprintf(stderr, "Error: cannot allocate memory for a new socket set\n"); fprintf(stderr, "Error: cannot allocate memory for a new socket set\n");
@ -31,10 +143,11 @@ int handle_player(void *data) {
return -1; return -1;
} }
send_player_connect_event(connection_data->obj_id);
for (;;) { for (;;) {
char message[SERVER_MESSAGE_LEN]; char message[SERVER_MESSAGE_LEN];
int ready_sockets = SDLNet_CheckSockets(set, 100);
int ready_sockets = SDLNet_CheckSockets(set, 10);
if (ready_sockets == -1) { if (ready_sockets == -1) {
fprintf(stderr, "Error: cannot call select() system call with SDLNet_CheckSockets()\n"); fprintf(stderr, "Error: cannot call select() system call with SDLNet_CheckSockets()\n");
continue; continue;
@ -44,65 +157,29 @@ int handle_player(void *data) {
goto update_client; goto update_client;
int recv_len = SDLNet_TCP_Recv(connection_data->socket, message, SERVER_MESSAGE_LEN); int recv_len = SDLNet_TCP_Recv(connection_data->socket, message, SERVER_MESSAGE_LEN);
if (!recv_len) { if (!recv_len) {
// player disconnected // player disconnected
fprintf(stderr, "Error: failed receiving message\n%s\n", SDLNet_GetError()); fprintf(stderr, "Error: failed receiving message\n%s\n", SDLNet_GetError());
break; break;
} }
if (DEBUG) if (DEBUG & GENERAL_DEBUG)
fprintf(stdout, "Notice: received '%s' and '%d' bytes\n", message, recv_len); fprintf(stdout, "Notice: received '%s' and '%d' bytes\n", message, recv_len);
// parsing the message handle_player_input(obj, message);
uint8_t action = message[0];
switch (action) {
case RIGHT_MOVEMENT:
obj->x += MOVEMENT_SPEED;
break;
case LEFT_MOVEMENT:
obj->x -= MOVEMENT_SPEED;
break;
case JUMP_MOVEMENT:
obj->force -= MOVEMENT_SPEED * 2.5;
obj->colliding = 0;
break;
case CROUCH_MOVEMENT: // TODO
break;
default:
break;
}
update_client: update_client:
if (obj->y < 200) { handle_player_physics(obj);
obj->force += GRAVITY; send_player_positions(connection_data->socket, connection_data->obj_id);
} else {
obj->colliding = 1;
// obj->force = 0;
obj->y = 200;
} }
// gravity // Communicate client disconnect
obj->y += obj->force; send_player_disconnect_event(connection_data->obj_id);
// Update the client with information
// Note: the order OBVIOUSLY matters
int reply[] = {
obj->x,
obj->y,
obj->colliding,
obj->force
};
if (DEBUG)
fprintf(stdout, "Notice: new player properties (%d, %d, %d, %d)\n", reply[0], reply[1], reply[2], reply[3]);
SDLNet_TCP_Send(connection_data->socket, reply, sizeof(int)*CLIENT_MESSAGE_LEN);
}
SDLNet_FreeSocketSet(set); SDLNet_FreeSocketSet(set);
SDLNet_TCP_Close(connection_data->socket); SDLNet_TCP_Close(connection_data->socket);
objects_map[connection_data->obj_id] = NULL;
connections_map[connection_data->id] = NULL;
free(obj); free(obj);
free(data); free(data);
@ -114,6 +191,25 @@ void catch_alarm(int sig) {
exit(EXIT_SUCCESS); 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[]) { int main(int argc, char *argv[]) {
signal(SIGINT, catch_alarm); signal(SIGINT, catch_alarm);
@ -148,7 +244,11 @@ int main(int argc, char *argv[]) {
fprintf(stdout, "Notice: accepted a connection from client!\n"); fprintf(stdout, "Notice: accepted a connection from client!\n");
objects_map = (struct object **) realloc(objects_map, sizeof(struct object *)*(objects_count+1)); 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) { if (objects_map == NULL) {
fprintf(stderr, "Error: failed reallocating objects hash map\n"); fprintf(stderr, "Error: failed reallocating objects hash map\n");
return -1; return -1;
@ -160,7 +260,15 @@ int main(int argc, char *argv[]) {
return -1; return -1;
} }
objects_map[objects_count] = new_object; 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 connection *new_connection = (struct connection *) calloc(1, sizeof(struct connection)); struct connection *new_connection = (struct connection *) calloc(1, sizeof(struct connection));
if (new_connection == NULL) { if (new_connection == NULL) {
@ -168,11 +276,15 @@ int main(int argc, char *argv[]) {
return -1; return -1;
} }
new_object->id = objects_count; 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 = objects_count; new_connection->obj_id = new_object_position;
objects_count++; if (DEBUG & PLAYER_DEBUG)
fprintf(stdout, "Notice: new player object id: %d\n", new_object_position);
SDL_CreateThread(handle_player, "client", new_connection); SDL_CreateThread(handle_player, "client", new_connection);
} }

View File

@ -4,8 +4,9 @@
#include <SDL2/SDL_net.h> #include <SDL2/SDL_net.h>
struct connection { struct connection {
TCPsocket socket; int id;
int obj_id; int obj_id;
TCPsocket socket;
}; };
struct object { struct object {
@ -15,6 +16,8 @@ struct object {
int colliding; int colliding;
int force; int force;
uint8_t state;
}; };
#endif #endif