Przeglądaj źródła

Progress on two way communication

Aaro Saila 1 miesiąc temu
rodzic
commit
1881792872

+ 23 - 11
src/common/game.c

@@ -28,20 +28,15 @@ const GameStateParameters game_default_params = {
 };
 
 GameState GameState_new(
-    // const float paddles_w,
-    // const float paddles_h,
-    // const float paddle_l_x,
-    // const float paddle_speed,
-    // const float ball_w,
-    // const vec2 ball_pos,
-    // const float ball_speed
-    const GameStateParameters params
+    const GameStateParameters params,
+    const bool ai_enabled
 ) {
 
 #define BALL_START_DIR { -1.0f, 0.0f }
 
     // clang-format off
     GameState state = {
+        .ai_enabled = ai_enabled,
         .paddle_l = {
             .pos = { params.paddle_l_x, 0.5f },
             .w = params.paddles_w,
@@ -81,7 +76,7 @@ static void paddle_collision_check(MovingObject *const paddle) {
     }
 }
 
-static void paddle_r_move(GameState *const state) {
+static void paddle_r_change_dir_ai(GameState *const state) {
     const float ball_y = state->ball.pos[1];
 
     const float target_zone_range = state->paddle_r.h / 2.0f;
@@ -257,7 +252,7 @@ static void ball_move(GameState *const state, const double delta) {
     glmc_vec2_copy(new_pos, state->ball.pos);
 }
 
-void GameState_move_paddle_l(GameState *const state, const SEDirection dir) {
+void GameState_paddle_l_change_dir(GameState *const state, const SEDirection dir) {
     switch (dir) {
     case SE_UP:
         state->paddle_l.dirv[1] = -1.0f;
@@ -272,6 +267,21 @@ void GameState_move_paddle_l(GameState *const state, const SEDirection dir) {
     }
 }
 
+void GameState_paddle_r_change_dir(GameState *const state, const SEDirection dir) {
+    switch (dir) {
+    case SE_UP:
+        state->paddle_r.dirv[1] = -1.0f;
+        break;
+    case SE_DOWN:
+        state->paddle_r.dirv[1] = 1.0f;
+        break;
+    case SE_NONE:
+        state->paddle_r.dirv[1] = 0.0f;
+    default:
+        break;
+    }
+}
+
 void GameState_update(GameState *const state, const double delta) {
     // Paddles
     vec2 paddle_movement;
@@ -280,7 +290,9 @@ void GameState_update(GameState *const state, const double delta) {
     glmc_vec2_add(state->paddle_l.pos, paddle_movement, state->paddle_l.pos);
     paddle_collision_check(&state->paddle_l);
 
-    paddle_r_move(state);
+    if (state->ai_enabled) {
+        paddle_r_change_dir_ai(state);
+    }
     glmc_vec2_scale(state->paddle_r.dirv, paddle_movement_scale, paddle_movement);
     glmc_vec2_add(state->paddle_r.pos, paddle_movement, state->paddle_r.pos);
     paddle_collision_check(&state->paddle_r);

+ 5 - 9
src/common/game.h

@@ -26,6 +26,7 @@ typedef struct {
 } GameStateParameters;
 
 typedef struct {
+    bool ai_enabled;
     MovingObject paddle_l;
     MovingObject paddle_r;
     MovingObject ball;
@@ -36,16 +37,11 @@ typedef struct {
 } GameState;
 
 GameState GameState_new(
-    // const float paddles_w,
-    // const float paddles_h,
-    // const float paddle_l_x,
-    // const float paddle_speed,
-    // const float ball_w,
-    // const vec2 ball_pos,
-    // const float ball_speed
-    const GameStateParameters params
+    const GameStateParameters params,
+    const bool ai_enabled
 );
-void GameState_move_paddle_l(GameState *const state, const SEDirection dir);
+void GameState_paddle_l_change_dir(GameState *const state, const SEDirection dir);
+void GameState_paddle_r_change_dir(GameState *const state, const SEDirection dir);
 void GameState_update(GameState *const state, const double delta);
 SEDirection GameState_paddle_l_dir_get(const GameState *const state);
 

+ 64 - 28
src/common/networking.c

@@ -1,4 +1,6 @@
 #include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
 
 #include "scufeng/log.h"
 
@@ -8,26 +10,38 @@ static const uint8_t fb = 0xfb;
 static const uint8_t fe = 0xfe;
 
 void PaddleChangeDirMsg_encode(const PaddleChangeDirMsg *const msg, uint8_t *buf, const size_t buf_size) {
-    if (buf_size < PADDLE_CHANGE_DIR_MSG_ENCODED_SIZE) {
-        LOG_FATALF("Buffer size too small (%zu), %zu required.", buf_size, PADDLE_CHANGE_DIR_MSG_ENCODED_SIZE);
+    if (buf_size < sizeof(PaddleChangeDirMsg)) {
+        LOG_FATALF("Buffer size too small (%zu), %zu required.", buf_size, sizeof(PaddleChangeDirMsg));
     }
 
-    memcpy(buf, &msg->dir, sizeof(msg->dir));
-    buf += sizeof(msg->dir);
-    memcpy(buf, &msg->player1, sizeof(msg->player1));
+    memcpy(buf, msg, sizeof(PaddleChangeDirMsg));
 }
 
 PaddleChangeDirMsg PaddleChangeDir_decode(const uint8_t *buf, const size_t buf_size) {
-    if (buf_size < PADDLE_CHANGE_DIR_MSG_ENCODED_SIZE) {
-        LOG_FATALF("Buffer size too small (%zu), %zu required.", buf_size, PADDLE_CHANGE_DIR_MSG_ENCODED_SIZE);
+    if (buf_size < sizeof(PaddleChangeDirMsg)) {
+        LOG_FATALF("Buffer size too small (%zu), %zu required.", buf_size, sizeof(PaddleChangeDirMsg));
     }
 
-    PaddleChangeDirMsg msg = {0};
+    PaddleChangeDirMsg msg = { 0 };
+    memcpy(&msg, buf, sizeof(PaddleChangeDirMsg));
 
-    memcpy(&msg.dir, buf, sizeof(msg.dir));
-    buf += sizeof(msg.dir);
-    memcpy(&msg.player1, buf, sizeof(msg.player1));
+    return msg;
+}
 
+void PaddlePosMsg_encode(const PaddlePosMsg *const msg, uint8_t *buf, const size_t buf_size) {
+    if (buf_size < sizeof(PaddlePosMsg)) {
+        LOG_FATALF("Buffer size too small (%zu), %zu required.", buf_size, sizeof(PaddlePosMsg));
+    }
+
+    memcpy(buf, msg, buf_size);
+}
+
+PaddlePosMsg PaddlePosMsg_decode(const uint8_t *buf, const size_t buf_size) {
+    if (buf_size < sizeof(PaddlePosMsg)) {
+        LOG_FATALF("Buffer size too small (%zu), %zu required.", buf_size, sizeof(PaddlePosMsg));
+    }
+    PaddlePosMsg msg = { 0 };
+    memcpy(&msg, buf, sizeof(PaddlePosMsg));
     return msg;
 }
 
@@ -35,7 +49,10 @@ void send_msg(FILE *s, const uint8_t *const buf, const size_t buf_size) {
     uint8_t *buf_cpy = (uint8_t *) malloc(sizeof(uint8_t) * buf_size);
     memcpy(buf_cpy, buf, buf_size);
     for (uint8_t *p = buf_cpy; p < buf_cpy + buf_size; p++) {
-        if (*p == fb || *p == fe) {
+        // if (*p == fb || *p == fe) {
+        //     *p += SEND_FRAME_MANGLE;
+        // }
+        if (*p == fb) {
             *p += SEND_FRAME_MANGLE;
         }
     }
@@ -49,9 +66,9 @@ void send_msg(FILE *s, const uint8_t *const buf, const size_t buf_size) {
     if (fwrite(buf_cpy, buf_size, 1, s) < 1) {
         LOG_FATAL("[send_msg] Failed to write msg");
     }
-    if (fwrite(&fe, sizeof(fe), 1, s) < 1) {
-        LOG_FATAL("[send_msg] Failed to write fe");
-    }
+    // if (fwrite(&fe, sizeof(fe), 1, s) < 1) {
+    //     LOG_FATAL("[send_msg] Failed to write fe");
+    // }
     if (fflush(s) != 0) {
         LOG_FATAL("[send_msg] Failed to flush stream");
     }
@@ -59,12 +76,28 @@ void send_msg(FILE *s, const uint8_t *const buf, const size_t buf_size) {
     free(buf_cpy);
 }
 
-bool recv_msg(FILE *s, uint8_t *const buf, const size_t buf_size) {
-    uint8_t _fb;
-    if (fread(&_fb, sizeof(_fb), 1, s) < 1) {
-        LOG_FATAL("[recv_msg] Failed to read _fb");
+static bool recv_until_fb_or_empty_buf(FILE *s) {
+    while (true) {
+        uint8_t _fb;
+        if (fread(&_fb, sizeof(_fb), 1, s) < 1) {
+            if (errno == EWOULDBLOCK) {
+                return false;
+            } else {
+                printf("errno: %d ferror: %d feof: %d\n", errno, ferror(s), feof(s));
+                LOG_FATAL("[recv_msg] Failed to read _fb");
+            }
+        }
+        if (_fb != fb) {
+            continue;
+        } else {
+            return true;
+        }
     }
-    if (_fb != fb) {
+}
+
+bool recv_msg(FILE *s, uint8_t *const buf, const size_t buf_size) {
+    bool found_fb = recv_until_fb_or_empty_buf(s);
+    if (!found_fb) {
         return false;
     }
 
@@ -80,18 +113,21 @@ bool recv_msg(FILE *s, uint8_t *const buf, const size_t buf_size) {
         LOG_FATAL("[recv_msg] Failed to read msg");
     }
     for (uint8_t *p = buf; p < buf + buf_size; p++) {
-        if (*p == fb + SEND_FRAME_MANGLE || *p == fe + SEND_FRAME_MANGLE) {
+        // if (*p == fb + SEND_FRAME_MANGLE || *p == fe + SEND_FRAME_MANGLE) {
+        //     *p += RECV_FRAME_MANGLE;
+        // }
+        if (*p == fb + SEND_FRAME_MANGLE) {
             *p += RECV_FRAME_MANGLE;
         }
     }
 
-    uint8_t _fe;
-    if (fread(&_fe, sizeof(_fe), 1, s) < 1) {
-        LOG_FATAL("[recv_msg] Failed to read _fe");
-    }
-    if (_fe != fe) {
-        return false;
-    }
+    // uint8_t _fe;
+    // if (fread(&_fe, sizeof(_fe), 1, s) < 1) {
+    //     LOG_FATAL("[recv_msg] Failed to read _fe");
+    // }
+    // if (_fe != fe) {
+    //     return false;
+    // }
 
     return true;
 }

+ 14 - 2
src/common/networking.h

@@ -4,17 +4,29 @@
 #include <stdint.h>
 #include <stddef.h>
 
-#define PADDLE_CHANGE_DIR_MSG_ENCODED_SIZE (sizeof(uint8_t) * 2)
 
 #define SEND_FRAME_MANGLE ((uint8_t) 10)
 #define RECV_FRAME_MANGLE (-(SEND_FRAME_MANGLE))
 
-typedef struct {
+typedef enum {
+    NET_MSG_PADDLE_CHANGE_DIR,
+    NET_MSG_PADDLE_POS
+} NetMsgType;
+
+typedef struct [[gnu::packed]] {
     uint8_t dir;     // SEDirection
     uint8_t player1; // bool
 } PaddleChangeDirMsg;
 
+typedef struct [[gnu::packed]] {
+    float pos_x;
+    float pos_y;
+    uint8_t player1; // bool
+} PaddlePosMsg;
+
 void PaddleChangeDirMsg_encode(const PaddleChangeDirMsg *const msg, uint8_t *const buf, const size_t buf_size);
 PaddleChangeDirMsg PaddleChangeDir_decode(const uint8_t *buf, const size_t buf_size);
+void PaddlePosMsg_encode(const PaddlePosMsg *const msg, uint8_t *buf, const size_t buf_size);
+PaddlePosMsg PaddlePosMsg_decode(const uint8_t *buf, const size_t buf_size);
 void send_msg(FILE *s, const uint8_t *const buf, const size_t buf_size);
 bool recv_msg(FILE *s, uint8_t *const buf, const size_t buf_size);

+ 35 - 34
src/game/MultiPlayer.c

@@ -1,3 +1,4 @@
+#include <asm-generic/errno.h>
 #include <stdio.h>
 #include <sys/socket.h>
 #include <netdb.h>
@@ -6,9 +7,10 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 #include "scufeng/log.h"
-#include "scufeng/Shape.h"
+#include "cglm/call/vec2.h"
 
 #include "networking.h"
 #include "MultiPlayer.h"
@@ -26,7 +28,7 @@ MultiPlayer MultiPlayer_alloc(
     mp.screen_w = screen_w;
     mp.screen_h = screen_h;
 
-    mp.state = GameState_new(game_default_params);
+    mp.state = GameState_new(game_default_params, false);
     mp.shapes = GameShapes_alloc(screen_w, screen_h, game_default_params);
 
     struct protoent *proto = getprotobyname("tcp");
@@ -55,6 +57,9 @@ MultiPlayer MultiPlayer_alloc(
     if (res == -1) {
         LOG_FATALF("connect failed: %d %s", errno, strerror(errno));
     }
+    if (fcntl(mp.sock, F_SETFL, O_NONBLOCK) != 0) {
+        LOG_FATALF("fcntl failed on mp.sock: (%d) %s", errno, strerror(errno));
+    }
 
     mp.conn_s = fdopen(mp.sock, "r+");
     if (mp.conn_s == nullptr) {
@@ -75,33 +80,6 @@ void MultiPlayer_free(MultiPlayer *const mp) {
     GameShapes_free(&mp->shapes);
 }
 
-static void pos_convert(
-    vec3 render_pos,
-    const vec3 state_pos,
-    const unsigned int screen_w,
-    const unsigned int screen_h
-) {
-    render_pos[0] = state_pos[0] * screen_w;
-    render_pos[1] = (1.0f - state_pos[1]) * screen_h;
-}
-
-static void update_shapes(
-    const GameState *const state,
-    SEMesh *const paddle_l,
-    SEMesh *const paddle_r,
-    SEMesh *const ball,
-    const unsigned int screen_w,
-    const unsigned int screen_h
-) {
-
-    // Paddles
-    pos_convert(paddle_l->transform.pos, state->paddle_l.pos, screen_w, screen_h);
-    pos_convert(paddle_r->transform.pos, state->paddle_r.pos, screen_w, screen_h);
-
-    // Ball
-    pos_convert(ball->transform.pos, state->ball.pos, screen_w, screen_h);
-}
-
 void MultiPlayer_tick(MultiPlayer *const mp, const double delta) {
     SEDirection new_dir = SE_NONE;
     bool dir_changed = false;
@@ -122,18 +100,41 @@ void MultiPlayer_tick(MultiPlayer *const mp, const double delta) {
     }
 
     if (dir_changed) {
-        GameState_move_paddle_l(&mp->state, new_dir);
+        GameState_paddle_l_change_dir(&mp->state, new_dir);
         const PaddleChangeDirMsg msg = {
             .dir = (uint8_t) new_dir,
             .player1 = (uint8_t) true
         };
 
-        uint8_t buf[PADDLE_CHANGE_DIR_MSG_ENCODED_SIZE];
-        PaddleChangeDirMsg_encode(&msg, buf, PADDLE_CHANGE_DIR_MSG_ENCODED_SIZE);
-        send_msg(mp->conn_s, buf, PADDLE_CHANGE_DIR_MSG_ENCODED_SIZE);
+        uint8_t buf[sizeof(PaddleChangeDirMsg)];
+        PaddleChangeDirMsg_encode(&msg, buf, sizeof(PaddleChangeDirMsg));
+        send_msg(mp->conn_s, buf, sizeof(PaddleChangeDirMsg));
     }
 
-    // last_dir = new_direction;
+    uint8_t res_buf[sizeof(PaddlePosMsg)];
+    if (recv_msg(mp->conn_s, res_buf, sizeof(res_buf))) {
+        const PaddlePosMsg msg = PaddlePosMsg_decode(res_buf, sizeof(res_buf));
+        vec2 pos = { msg.pos_x, msg.pos_y };
+        const bool player1 = (bool) msg.player1;
+        printf("Got msg from server: player1: %d, pos: (%.2lf, %.2lf)\n", player1, pos[0], pos[1]);
+        glmc_vec2_copy(pos, mp->state.paddle_l.pos);
+        mp->state.paddle_l.pos[0] = pos[0];
+        mp->state.paddle_l.pos[1] = pos[1];
+    }
+    // size_t items_read = fread(res_buf, sizeof(res_buf), 1, mp->conn_s);
+    // if (items_read < 1) {
+    //     if (errno != EWOULDBLOCK) {
+    //         LOG_FATALF("Failed to receive from server: (%d) %s", errno, strerror(errno));
+    //     }
+    // } else {
+    //     const PaddlePosMsg msg = PaddlePosMsg_decode(res_buf, sizeof(res_buf));
+    //     vec2 pos = { msg.pos_x, msg.pos_y };
+    //     const bool player1 = (bool) msg.player1;
+    //     printf("Got msg from server: player1: %d, pos: (%.2lf, %.2lf)\n", player1, pos[0], pos[1]);
+    //     glmc_vec2_copy(pos, mp->state.paddle_l.pos);
+    //     mp->state.paddle_l.pos[0] = pos[0];
+    //     mp->state.paddle_l.pos[1] = pos[1];
+    // }
 
     GameState_update(&mp->state, delta);
     GameShapes_update(&mp->shapes, &mp->state, mp->screen_w, mp->screen_h);

+ 5 - 5
src/game/SinglePlayer.c

@@ -13,7 +13,7 @@ SinglePlayer SinglePlayer_alloc(
     SinglePlayer sp = {
         .screen_w = screen_w,
         .screen_h = screen_h,
-        .state = GameState_new(params),
+        .state = GameState_new(params, true),
         .paddle_l = SEMesh_rect_color_alloc(GLM_VEC4_ONE),
         .paddle_r = SEMesh_rect_color_alloc(GLM_VEC4_ONE),
         .ball = SEMesh_rect_color_alloc(GLM_VEC4_ONE),
@@ -43,7 +43,7 @@ SinglePlayer SinglePlayer_alloc_default(
     SinglePlayer sp = {
         .screen_w = screen_w,
         .screen_h = screen_h,
-        .state = GameState_new(game_default_params),
+        .state = GameState_new(game_default_params, true),
         .paddle_l = SEMesh_rect_color_alloc(GLM_VEC4_ONE),
         .paddle_r = SEMesh_rect_color_alloc(GLM_VEC4_ONE),
         .ball = SEMesh_rect_color_alloc(GLM_VEC4_ONE),
@@ -108,11 +108,11 @@ static void update_shapes(
 
 static bool key_input_handle(GameState *const state) {
     if (se_get_key(SE_KEY_W) == SE_KEY_ACTION_PRESS) {
-        GameState_move_paddle_l(state, SE_UP);
+        GameState_paddle_l_change_dir(state, SE_UP);
     } else if (se_get_key(SE_KEY_S) == SE_KEY_ACTION_PRESS) {
-        GameState_move_paddle_l(state, SE_DOWN);
+        GameState_paddle_l_change_dir(state, SE_DOWN);
     } else {
-        GameState_move_paddle_l(state, SE_NONE);
+        GameState_paddle_l_change_dir(state, SE_NONE);
     }
 
     if (se_get_key(SE_KEY_ESCAPE) == SE_KEY_ACTION_PRESS) {

+ 24 - 18
src/server/server.c

@@ -8,7 +8,6 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <stdint.h>
-#include <stdlib.h>
 
 #include "scufeng/engine.h"
 #include "scufeng/log.h"
@@ -33,9 +32,9 @@ static void server_lobby(const int sock) {
     if (player1 == -1) {
         LOG_FATALF("accept failed: %s", strerror(errno));
     }
-    // if (fcntl(player1, F_SETFL, O_NONBLOCK) != 0) {
-    //     LOG_FATALF("fcntl failed on player1: (%d) %s", errno, strerror(errno));
-    // }
+    if (fcntl(player1, F_SETFL, O_NONBLOCK) != 0) {
+        LOG_FATALF("fcntl failed on player1: (%d) %s", errno, strerror(errno));
+    }
     printf("Player 1 connected\n");
 
     p1_conn = fdopen(player1, "r+");
@@ -59,7 +58,7 @@ static void server_lobby(const int sock) {
 }
 
 static void server_game() {
-    GameState state = GameState_new(game_default_params);
+    GameState state = GameState_new(game_default_params, false);
 
     se_fps_lock_set_fps(60);
 
@@ -70,19 +69,26 @@ static void server_game() {
         se_fps_lock_frame_start_s(current_time_s);
 
         // Player input
-        uint8_t buf[PADDLE_CHANGE_DIR_MSG_ENCODED_SIZE];
-        if (!recv_msg(p1_conn, buf, PADDLE_CHANGE_DIR_MSG_ENCODED_SIZE)) {
-            LOG_FATAL("Failed to receive message");
-        }
-
-        PaddleChangeDirMsg msg = PaddleChangeDir_decode(buf, PADDLE_CHANGE_DIR_MSG_ENCODED_SIZE);
-        SEDirection dir = (SEDirection) msg.dir;
-        bool player1 = (bool) msg.player1;
-        if (player1) {
-            const char *dir_str = dir == SE_UP ? "UP" : (dir == SE_DOWN ? "DOWN" : (dir == SE_NONE ? "NONE" : "INVALID"));
-            printf("Player 1 moves paddle to direction: %s\n", dir_str);
-        } else {
-            printf("Message was not from player1\n");
+        uint8_t buf[sizeof(PaddleChangeDirMsg)];
+        if (recv_msg(p1_conn, buf, sizeof(buf))) {
+            PaddleChangeDirMsg msg = PaddleChangeDir_decode(buf, sizeof(buf));
+            SEDirection dir = (SEDirection) msg.dir;
+            bool player1 = (bool) msg.player1;
+            if (player1) {
+                const char *dir_str = dir == SE_UP ? "UP" : (dir == SE_DOWN ? "DOWN" : (dir == SE_NONE ? "NONE" : "INVALID"));
+                printf("Player 1 moves paddle to direction: %s\n", dir_str);
+                GameState_paddle_l_change_dir(&state, dir);
+                PaddlePosMsg res_msg = {
+                    .pos_x = state.paddle_l.pos[0],
+                    .pos_y = state.paddle_l.pos[1],
+                    .player1 = (uint8_t) true
+                };
+                uint8_t res_buf[sizeof(PaddlePosMsg)];
+                PaddlePosMsg_encode(&res_msg, res_buf, sizeof(res_buf));
+                send_msg(p1_conn, res_buf, sizeof(res_buf));
+            } else {
+                printf("Message was not from player1\n");
+            }
         }
 
         // Tick