From 7dccfbaa8d899987820d42c3535a100c428ccdce Mon Sep 17 00:00:00 2001 From: iWas-Coder Date: Sun, 31 Mar 2024 22:11:34 +0200 Subject: [PATCH] Abstracting away the game state, scenes, and lobbies WIP, not finished yet. --- include/sk_lobby.h | 41 ++++++++++++++ include/sk_renderer.h | 6 +- include/{sk_gametypes.h => sk_scene.h} | 16 ++---- include/sk_server.h | 4 +- include/sk_state.h | 45 +++++++++++++++ src/sk_client.c | 31 ++++++----- src/sk_lobby.c | 76 ++++++++++++++++++++++++++ src/sk_renderer_draw.c | 12 ++-- src/sk_renderer_update.c | 12 ++-- src/sk_scene.c | 22 ++++++++ src/sk_server.c | 10 +++- src/sk_state.c | 43 +++++++++++++++ 12 files changed, 275 insertions(+), 43 deletions(-) create mode 100644 include/sk_lobby.h rename include/{sk_gametypes.h => sk_scene.h} (83%) create mode 100644 include/sk_state.h create mode 100644 src/sk_lobby.c create mode 100644 src/sk_scene.c create mode 100644 src/sk_state.c diff --git a/include/sk_lobby.h b/include/sk_lobby.h new file mode 100644 index 0000000..212b584 --- /dev/null +++ b/include/sk_lobby.h @@ -0,0 +1,41 @@ +/* + * GNU Sparky --- A 5v5 character-based libre tactical shooter + * Copyright (C) 2024 Wasym A. Alonso + * + * This file is part of Sparky. + * + * Sparky is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Sparky is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Sparky. If not, see . + */ + + +#pragma once + +#include +#include + +#define SK_LOBBY_MAX_PLAYERS 10 + +typedef struct { + u8 id; + u8 players_count; + sk_player players[SK_LOBBY_MAX_PLAYERS]; +} sk_lobby; + +sk_lobby sk_lobby_create(u8 id); + +void sk_lobby_destroy(sk_lobby *l); + +u8 sk_lobby_add(sk_lobby *l, sk_player p); + +u8 sk_lobby_kick(sk_lobby *l, i8 p_idx); diff --git a/include/sk_renderer.h b/include/sk_renderer.h index d530ce5..ae65d27 100644 --- a/include/sk_renderer.h +++ b/include/sk_renderer.h @@ -22,7 +22,7 @@ #pragma once #include -#include +#include #define sk_renderer_loop while (!WindowShouldClose()) @@ -30,6 +30,6 @@ void sk_renderer_create(void); void sk_renderer_destroy(void); -void sk_renderer_update(State *s); +void sk_renderer_update(sk_state *s); -void sk_renderer_draw(State *s); +void sk_renderer_draw(sk_state *s); diff --git a/include/sk_gametypes.h b/include/sk_scene.h similarity index 83% rename from include/sk_gametypes.h rename to include/sk_scene.h index c0c340c..216a132 100644 --- a/include/sk_gametypes.h +++ b/include/sk_scene.h @@ -21,15 +21,11 @@ #pragma once -#include - typedef enum { - SCENE_MAIN_MENU, - SCENE_GAMEPLAY -} Scene; + SK_SCENE_KIND_MAIN_MENU, + SK_SCENE_KIND_GAMEPLAY +} sk_scene_kind; -typedef struct State { - Scene current_scene; - sk_player player; - u8 is_online; -} State; +typedef struct { + sk_scene_kind kind; +} sk_scene; diff --git a/include/sk_server.h b/include/sk_server.h index 25178be..7bc26d1 100644 --- a/include/sk_server.h +++ b/include/sk_server.h @@ -27,7 +27,7 @@ #define SK_SERVER_PORT 27015 #define SK_SERVER_TICK_RATE 128 #define SK_SERVER_MSG_MAX_SIZE 1024 -#define SK_SERVER_MSG_CONN_REQ "ping::" SK_SERVER_NAME -#define SK_SERVER_MSG_CONN_RES "pong::" SK_SERVER_NAME +#define SK_SERVER_MSG_CONN_REQ SK_SERVER_NAME "::ping" +#define SK_SERVER_MSG_CONN_RES SK_SERVER_NAME "::pong::%u/%u" u8 sk_server_run(void); diff --git a/include/sk_state.h b/include/sk_state.h new file mode 100644 index 0000000..7989357 --- /dev/null +++ b/include/sk_state.h @@ -0,0 +1,45 @@ +/* + * GNU Sparky --- A 5v5 character-based libre tactical shooter + * Copyright (C) 2024 Wasym A. Alonso + * + * This file is part of Sparky. + * + * Sparky is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Sparky is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Sparky. If not, see . + */ + + +#pragma once + +#include +#include + +#define SK_STATE_MAX_LOBBIES 256 + +typedef struct { + u8 is_online; + sk_scene curr_scene; + union { + struct { + u8 lobbies_count; + sk_lobby lobbies[SK_STATE_MAX_LOBBIES]; + }; + struct { + sk_player player; + }; + }; +} sk_state; + +sk_state sk_state_create(u8 is_online); + +void sk_state_destroy(sk_state *s); diff --git a/src/sk_client.c b/src/sk_client.c index 6805b60..dc40f82 100644 --- a/src/sk_client.c +++ b/src/sk_client.c @@ -23,18 +23,17 @@ #include #include #include +#include #include #include #include #include #include #include -#include - -static State state = {0}; u8 sk_client_run(const char *ip) { TraceLog(LOG_INFO, "Initializing %s", SK_CLIENT_NAME); + u8 is_online = 0; int sock_fd; if (!ip) TraceLog(LOG_WARNING, "Running in offline mode"); else { @@ -68,9 +67,9 @@ u8 sk_client_run(const char *ip) { } pong_msg[pong_msg_n] = 0; if (!strcmp(pong_msg, SK_SERVER_MSG_CONN_RES)) { - state.is_online = 1; + is_online = 1; } - if (!state.is_online) { + if (!is_online) { TraceLog(LOG_ERROR, "Unable to communicate with `%s`. Exiting...", ip); close(sock_fd); return 1; @@ -80,16 +79,20 @@ u8 sk_client_run(const char *ip) { if (!ChangeDirectory(GetApplicationDirectory())) { TraceLog(LOG_WARNING, "Could not change CWD to the game's root directory"); } - sk_renderer_create(); - state.current_scene = SCENE_MAIN_MENU; - state.player = sk_player_create(SK_PLAYER_KIND_JETT); - sk_renderer_loop { - sk_renderer_update(&state); - sk_renderer_draw(&state); + sk_state state = sk_state_create(is_online); + if (!is_online) { + sk_renderer_create(); + sk_renderer_loop { + sk_renderer_update(&state); + sk_renderer_draw(&state); + } + sk_player_destroy(&state.player); + sk_renderer_destroy(); + } + else { + TraceLog(LOG_WARNING, "Not implemented yet"); } - sk_player_destroy(&state.player); - sk_renderer_destroy(); - if (state.is_online) close(sock_fd); + if (is_online) close(sock_fd); TraceLog(LOG_INFO, "%s closed successfully", SK_CLIENT_NAME); return 0; } diff --git a/src/sk_lobby.c b/src/sk_lobby.c new file mode 100644 index 0000000..b0fa760 --- /dev/null +++ b/src/sk_lobby.c @@ -0,0 +1,76 @@ +/* + * GNU Sparky --- A 5v5 character-based libre tactical shooter + * Copyright (C) 2024 Wasym A. Alonso + * + * This file is part of Sparky. + * + * Sparky is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Sparky is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Sparky. If not, see . + */ + + +#include + +sk_lobby sk_lobby_create(u8 id) { + sk_lobby l = { + .id = id, + .players_count = 0 + }; + for (u8 i = 0; i < SK_LOBBY_MAX_PLAYERS; ++i) { + l.players[i] = (sk_player) { + .lobby_id = -1, + .lobby_slot_idx = -1 + }; + } + return l; +} + +void sk_lobby_destroy(sk_lobby *l) { + (void) l; +} + +u8 sk_lobby_add(sk_lobby *l, sk_player p) { + if (l->players_count == SK_LOBBY_MAX_PLAYERS) { + TraceLog(LOG_DEBUG, "Lobby %u :: unable to add more players (full)", l->id); + return false; + } + for (u8 i = 0; i < SK_LOBBY_MAX_PLAYERS; ++i) { + if (l->players[i].lobby_id != -1 && + l->players[i].lobby_slot_idx != -1 ) continue; + p.lobby_id = l->id; + p.lobby_slot_idx = i; + l->players[i] = p; + TraceLog(LOG_INFO, "Lobby %u :: added new player to slot %u/%u", + l->id, + i + 1, + SK_LOBBY_MAX_PLAYERS); + } + ++l->players_count; + return true; +} + +u8 sk_lobby_kick(sk_lobby *l, i8 p_idx) { + if (p_idx >= l->players_count || + l->players[p_idx].lobby_id != l->id || + l->players[p_idx].lobby_slot_idx != p_idx) { + TraceLog(LOG_DEBUG, "Lobby %u :: unable to kick non-existant player", l->id); + return false; + } + l->players[p_idx].lobby_id = -1; + l->players[p_idx].lobby_slot_idx = -1; + l->players[p_idx] = (sk_player) { + .lobby_id = -1, + .lobby_slot_idx = -1 + }; + return true; +} diff --git a/src/sk_renderer_draw.c b/src/sk_renderer_draw.c index 1a0411a..4abe4d8 100644 --- a/src/sk_renderer_draw.c +++ b/src/sk_renderer_draw.c @@ -60,7 +60,7 @@ static inline void __draw_walls(void) { DrawCube((Vector3) { 0, 2.5f, 16 }, 32, 5, 1, GOLD); } -static void __draw_gameplay_world(State *s) { +static void __draw_gameplay_world(sk_state *s) { ClearBackground(SKYBLUE); BeginMode3D(s->player.camera); sk_player_draw(&s->player); @@ -101,7 +101,7 @@ static inline void __draw_crosshair(void) { WHITE); } -static void __draw_gameplay_hud(State *s) { +static void __draw_gameplay_hud(sk_state *s) { __draw_fps(); __draw_frametime(); if (s->is_online) { @@ -111,13 +111,13 @@ static void __draw_gameplay_hud(State *s) { __draw_crosshair(); } -void sk_renderer_draw(State *s) { +void sk_renderer_draw(sk_state *s) { BeginDrawing(); - switch (s->current_scene) { - case SCENE_MAIN_MENU: + switch (s->curr_scene.kind) { + case SK_SCENE_KIND_MAIN_MENU: __draw_main_menu(); break; - case SCENE_GAMEPLAY: + case SK_SCENE_KIND_GAMEPLAY: __draw_gameplay_world(s); __draw_gameplay_hud(s); break; diff --git a/src/sk_renderer_update.c b/src/sk_renderer_update.c index cd9a249..78afa3a 100644 --- a/src/sk_renderer_update.c +++ b/src/sk_renderer_update.c @@ -24,20 +24,20 @@ #include #include -static void __update_main_menu(State *s) { +static void __update_main_menu(sk_state *s) { if (IsKeyPressed(KEY_ENTER)) { - s->current_scene = SCENE_GAMEPLAY; + s->curr_scene.kind = SK_SCENE_KIND_GAMEPLAY; sk_player_load(&s->player, SK_WEAPON_KIND_7MM); DisableCursor(); } } -void sk_renderer_update(State *s) { - switch (s->current_scene) { - case SCENE_MAIN_MENU: +void sk_renderer_update(sk_state *s) { + switch (s->curr_scene.kind) { + case SK_SCENE_KIND_MAIN_MENU: __update_main_menu(s); break; - case SCENE_GAMEPLAY: + case SK_SCENE_KIND_GAMEPLAY: if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) sk_weapon_shoot(&s->player.weapon); sk_player_jump(&s->player); sk_player_move(&s->player, sk_player_peek(&s->player)); diff --git a/src/sk_scene.c b/src/sk_scene.c new file mode 100644 index 0000000..6d644ee --- /dev/null +++ b/src/sk_scene.c @@ -0,0 +1,22 @@ +/* + * GNU Sparky --- A 5v5 character-based libre tactical shooter + * Copyright (C) 2024 Wasym A. Alonso + * + * This file is part of Sparky. + * + * Sparky is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Sparky is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Sparky. If not, see . + */ + + +#include diff --git a/src/sk_server.c b/src/sk_server.c index f64c6c9..72ebd96 100644 --- a/src/sk_server.c +++ b/src/sk_server.c @@ -19,6 +19,7 @@ */ +#include #include #include #include @@ -98,8 +99,14 @@ u8 sk_server_run(void) { msg[msg_n] = 0; if (!strcmp(msg, SK_SERVER_MSG_CONN_REQ)) { TraceLog(LOG_INFO, "Connection from client (%s:%d) requested", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); + // TODO: check if there is a free slot in a lobby + u8 lobby_id = 0; + u8 lobby_slot_id = 0; + // TODO: assign him a lobby and a player slot inside it + memset(msg, 0, sizeof(msg)); + sprintf(msg, SK_SERVER_MSG_CONN_RES, lobby_id, lobby_slot_id); if (sendto(sock_fd, - SK_SERVER_MSG_CONN_RES, + msg, strlen(SK_SERVER_MSG_CONN_RES), 0, (struct sockaddr *) &client_addr, @@ -108,7 +115,6 @@ u8 sk_server_run(void) { continue; } TraceLog(LOG_INFO, "Connection from client (%s:%d) accepted", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); - // TODO: assign him a lobby with a free slot to be in } wait_next_tick(dt); } diff --git a/src/sk_state.c b/src/sk_state.c new file mode 100644 index 0000000..e42188a --- /dev/null +++ b/src/sk_state.c @@ -0,0 +1,43 @@ +/* + * GNU Sparky --- A 5v5 character-based libre tactical shooter + * Copyright (C) 2024 Wasym A. Alonso + * + * This file is part of Sparky. + * + * Sparky is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Sparky is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Sparky. If not, see . + */ + + +#include + +sk_state sk_state_create(u8 is_online) { + sk_state s = { + .is_online = is_online, + .curr_scene = (sk_scene) { .kind = SK_SCENE_KIND_MAIN_MENU } + }; + if (is_online) { + s.lobbies_count = 0; + for (u16 i = 0; i < SK_STATE_MAX_LOBBIES; ++i) { + s.lobbies[i] = sk_lobby_create(i); + } + } + else { + s.player = sk_player_create(SK_PLAYER_KIND_JETT); + } + return s; +} + +void sk_state_destroy(sk_state *s) { + (void) s; +}