Przeglądaj źródła

Working movement reporting to server

Aaro Saila 1 miesiąc temu
rodzic
commit
d517e8cd2a

+ 20 - 4
meson.build

@@ -13,6 +13,15 @@ c_args = [
   '-pedantic'
 ]
 
+common_src = [
+  'src/common/game.c',
+  'src/common/networking.c'
+]
+
+common_include = include_directories(
+  'src/common/'
+)
+
 scufeng_dep = dependency(
   'scufeng', 
   allow_fallback: true
@@ -20,15 +29,15 @@ scufeng_dep = dependency(
 
 game = executable(
   'game',
-  'src/common/game.c',
   'src/game/MainMenu.c',
   'src/game/MultiPlayer.c',
   'src/game/SinglePlayer.c',
   'src/game/pong.c',
   'src/game/screen.c',
-  include_directories: include_directories(
-    'src/common/'
-  ),
+  common_src,
+  include_directories: [
+    common_include
+  ],
   c_args: [
     c_args,
     '-DFONT_PATH="../assets/LiberationSans-Regular.ttf"',
@@ -45,10 +54,17 @@ game = executable(
 server = executable(
   'server',
   'src/server/server.c',
+  common_src,
+  include_directories: [
+    common_include
+  ],
   c_args: [
     c_args,
     '-D_DEFAULT_SOURCE' # for inet_aton
   ],
+  link_args: [
+    '-lm'
+  ],
   dependencies: [
     scufeng_dep
   ]

+ 61 - 32
src/common/game.c

@@ -4,19 +4,38 @@
 #include "scufeng/engine.h"
 #include "scufeng/util.h"
 
+// static const float paddles_w = 0.01f;
+// static const float paddles_h = 0.10f;
+// static const float paddle_l_x = (1.0f / 16);
+// static const float ball_w = paddles_w * 0.5f;
+// static vec2 ball_pos = { 0.5f, 0.5f };
+// static const float paddle_speed = 0.7f;
+// static const float ball_speed = 0.7f;
+
 typedef enum {
     BCR_PADDLE_L_GOAL,
     BCR_PADDLE_R_GOAL,
 } BALL_COLLISION_RESULT;
 
+const GameStateParameters game_default_params = {
+    .paddles_w = 0.01f,
+    .paddles_h = 0.10f,
+    .paddle_l_x = (1.0f / 16),
+    .ball_w = 0.005f,
+    .ball_pos = { 0.5f, 0.5f },
+    .paddle_speed = 0.7f,
+    .ball_speed = 0.7f,
+};
+
 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 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
 ) {
 
 #define BALL_START_DIR { -1.0f, 0.0f }
@@ -24,28 +43,28 @@ GameState GameState_new(
     // clang-format off
     GameState state = {
         .paddle_l = {
-            .pos = { paddle_l_x, 0.5f },
-            .w = paddles_w,
-            .h = paddles_h,
+            .pos = { params.paddle_l_x, 0.5f },
+            .w = params.paddles_w,
+            .h = params.paddles_h,
             .dirv = GLM_VEC2_ZERO_INIT,
-            .speed = paddle_speed
+            .speed = params.paddle_speed
         },
         .paddle_r = {
-            .pos = { 1.0f - paddle_l_x, 0.5f },
-            .w = paddles_w,
-            .h = paddles_h,
+            .pos = { 1.0f - params.paddle_l_x, 0.5f },
+            .w = params.paddles_w,
+            .h = params.paddles_h,
             .dirv = GLM_VEC2_ZERO_INIT,
-            .speed = paddle_speed
+            .speed = params.paddle_speed
         },
         .ball = {
             // .pos = { 0.5f, 0.5f },
-            .pos = { ball_pos[0], ball_pos[1] },
-            .w = ball_w,
-            .h = ball_w,
+            .pos = { params.ball_pos[0], params.ball_pos[1] },
+            .w = params.ball_w,
+            .h = params.ball_w,
             .dirv = BALL_START_DIR,
-            .speed = ball_speed
+            .speed = params.ball_speed
         },
-        .ball_start_pos = { ball_pos[0], ball_pos[1] },
+        .ball_start_pos = { params.ball_pos[0], params.ball_pos[1] },
         .ball_start_dir = BALL_START_DIR
     };
     // clang-format on
@@ -53,7 +72,7 @@ GameState GameState_new(
     return state;
 }
 
-static void paddle_collision_check(MovingObject* const paddle) {
+static void paddle_collision_check(MovingObject *const paddle) {
     if (paddle->pos[1] - paddle->h / 2.0f < 0.0f) {
         paddle->pos[1] = paddle->h / 2.0f;
     }
@@ -62,7 +81,7 @@ static void paddle_collision_check(MovingObject* const paddle) {
     }
 }
 
-static void paddle_r_move(GameState* const state) {
+static void paddle_r_move(GameState *const state) {
     const float ball_y = state->ball.pos[1];
 
     const float target_zone_range = state->paddle_r.h / 2.0f;
@@ -85,13 +104,13 @@ static void paddle_r_move(GameState* const state) {
     }
 }
 
-static void game_next_round(GameState* const state) {
+static void game_next_round(GameState *const state) {
     glmc_vec2_copy(state->ball_start_pos, state->ball.pos);
     glmc_vec2_copy(state->ball_start_dir, state->ball.dirv);
 }
 
-static bool ball_bounds_collision_check(GameState* const state, vec2 new_pos) {
-    MovingObject* const ball = &state->ball;
+static bool ball_bounds_collision_check(GameState *const state, vec2 new_pos) {
+    MovingObject *const ball = &state->ball;
 
     const float wd2 = ball->w / 2.0f;
     const float hd2 = ball->h / 2.0f;
@@ -118,16 +137,16 @@ static bool ball_bounds_collision_check(GameState* const state, vec2 new_pos) {
     return false;
 }
 
-static void ball_paddles_collision_check(GameState* const state, vec2 new_pos) {
+static void ball_paddles_collision_check(GameState *const state, vec2 new_pos) {
     static const float possible_y_directions[] = {
         0.0f,
         0.5f,
         -0.5f
     };
 
-    MovingObject* const ball = &state->ball;
-    const MovingObject* const paddle_l = &state->paddle_l;
-    const MovingObject* const paddle_r = &state->paddle_r;
+    MovingObject *const ball = &state->ball;
+    const MovingObject *const paddle_l = &state->paddle_l;
+    const MovingObject *const paddle_r = &state->paddle_r;
 
     const float ball_wd2 = ball->w / 2.0f;
     const float ball_hd2 = ball->h / 2.0f;
@@ -221,7 +240,7 @@ static void ball_paddles_collision_check(GameState* const state, vec2 new_pos) {
     }
 }
 
-static void ball_move(GameState* const state, const double delta) {
+static void ball_move(GameState *const state, const double delta) {
     vec2 ball_movement;
     const float ball_movement_scale = delta * state->ball.speed;
     // glmc_vec2_normalize(state->ball.dirv);
@@ -238,7 +257,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_move_paddle_l(GameState *const state, const SEDirection dir) {
     switch (dir) {
     case SE_UP:
         state->paddle_l.dirv[1] = -1.0f;
@@ -253,7 +272,7 @@ void GameState_move_paddle_l(GameState* const state, const SEDirection dir) {
     }
 }
 
-void GameState_update(GameState* const state, const double delta) {
+void GameState_update(GameState *const state, const double delta) {
     // Paddles
     vec2 paddle_movement;
     const float paddle_movement_scale = delta * state->paddle_l.speed;
@@ -269,3 +288,13 @@ void GameState_update(GameState* const state, const double delta) {
     // Ball
     ball_move(state, delta);
 }
+
+SEDirection GameState_paddle_l_dir_get(const GameState *const state) {
+    if (state->paddle_l.dirv[1] == -1.0f) {
+        return SE_UP;
+    } else if (state->paddle_l.dirv[1] == 1.0f) {
+        return SE_DOWN;
+    } else {
+        return SE_NONE;
+    }
+}

+ 21 - 7
src/common/game.h

@@ -15,6 +15,16 @@ typedef struct {
     float speed;
 } MovingObject;
 
+typedef struct {
+    float paddles_w;
+    float paddles_h;
+    float paddle_l_x;
+    float paddle_speed;
+    float ball_w;
+    vec2 ball_pos;
+    float ball_speed;
+} GameStateParameters;
+
 typedef struct {
     MovingObject paddle_l;
     MovingObject paddle_r;
@@ -26,15 +36,19 @@ 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 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
 );
 void GameState_move_paddle_l(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);
+
+extern const GameStateParameters game_default_params;
 
 #endif // GAME_H_

+ 97 - 0
src/common/networking.c

@@ -0,0 +1,97 @@
+#include <string.h>
+
+#include "scufeng/log.h"
+
+#include "networking.h"
+
+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);
+    }
+
+    memcpy(buf, &msg->dir, sizeof(msg->dir));
+    buf += sizeof(msg->dir);
+    memcpy(buf, &msg->player1, sizeof(msg->player1));
+}
+
+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);
+    }
+
+    PaddleChangeDirMsg msg = {0};
+
+    memcpy(&msg.dir, buf, sizeof(msg.dir));
+    buf += sizeof(msg.dir);
+    memcpy(&msg.player1, buf, sizeof(msg.player1));
+
+    return msg;
+}
+
+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) {
+            *p += SEND_FRAME_MANGLE;
+        }
+    }
+
+    if (fwrite(&fb, sizeof(fb), 1, s) < 1) {
+        LOG_FATAL("[send_msg] Failed to write fb");
+    }
+    if (fwrite(&buf_size, sizeof(buf_size), 1, s) < 1) {
+        LOG_FATAL("[send_msg] Failed to write msg_len");
+    }
+    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 (fflush(s) != 0) {
+        LOG_FATAL("[send_msg] Failed to flush stream");
+    }
+
+    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");
+    }
+    if (_fb != fb) {
+        return false;
+    }
+
+    size_t msg_len;
+    if (fread(&msg_len, sizeof(msg_len), 1, s) < 1) {
+        LOG_FATAL("[recv_msg] Failed to read msg_len");
+    }
+
+    if (buf_size < msg_len) {
+        LOG_FATALF("[recv_msg] Buffer too small. msg_len: %zu, buf_size: %zu", msg_len, buf_size);
+    }
+    if (fread(buf, buf_size, 1, s) < 1) {
+        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) {
+            *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;
+    }
+
+    return true;
+}

+ 20 - 0
src/common/networking.h

@@ -0,0 +1,20 @@
+#pragma once
+
+#include <stdio.h>
+#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 {
+    uint8_t dir;     // SEDirection
+    uint8_t player1; // bool
+} PaddleChangeDirMsg;
+
+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 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);

+ 45 - 28
src/game/MultiPlayer.c

@@ -7,9 +7,11 @@
 #include <arpa/inet.h>
 #include <unistd.h>
 
+#include "networking.h"
 #include "scufeng/log.h"
 
 #include "MultiPlayer.h"
+#include "game.h"
 
 MultiPlayer MultiPlayer_alloc(
     const char *server_host,
@@ -17,6 +19,8 @@ MultiPlayer MultiPlayer_alloc(
 ) {
     MultiPlayer mp;
 
+    mp.state = GameState_new(game_default_params);
+
     struct protoent *proto = getprotobyname("tcp");
     mp.sock = socket(AF_INET, SOCK_STREAM, proto->p_proto);
     if (mp.sock == -1) {
@@ -61,36 +65,49 @@ void MultiPlayer_free(MultiPlayer *const mp) {
     mp->sock = 0;
 }
 
-void MultiPlayer_tick(MultiPlayer *const mp) {
-    char buf[1024] = { 0 };
-    const size_t buf_size = sizeof(buf) / sizeof(buf[0]);
-    printf("Write msg: ");
-    fgets(buf, buf_size, stdin);
+void MultiPlayer_tick(MultiPlayer *const mp, const double delta) {
+    SEDirection new_dir = SE_NONE;
+    bool dir_changed = false;
+    const SEDirection current_dir = GameState_paddle_l_dir_get(&mp->state);
+    if (se_get_key(SE_KEY_W) == SE_KEY_ACTION_PRESS) {
+        if (current_dir != SE_UP) {
+            new_dir = SE_UP;
+            dir_changed = true;
+        }
+    } else if (se_get_key(SE_KEY_S) == SE_KEY_ACTION_PRESS) {
+        if (current_dir != SE_DOWN) {
+            new_dir = SE_DOWN;
+            dir_changed = true;
+        }
+    } else if (current_dir != SE_NONE) {
+        new_dir = SE_NONE;
+        dir_changed = true;
+    }
 
-    const size_t msg_len = strlen(buf) - 1;
+    if (dir_changed) {
+        GameState_move_paddle_l(&mp->state, new_dir);
+        const PaddleChangeDirMsg msg = {
+            .dir = (uint8_t) new_dir,
+            .player1 = (uint8_t) true
+        };
 
-    size_t items_written = fwrite(&msg_len, sizeof(msg_len), 1, mp->conn_s);
-    if (items_written < 1) {
-        LOG_FATALF("fwrite failed to write msg_len %zu", items_written);
-    }
-    if (fflush(mp->conn_s) == EOF) {
-        LOG_FATAL("fflush failed at msg_len");
-    }
-    printf("Sent %zu items\n", items_written);
+        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);
 
-    items_written = fwrite(buf, msg_len, 1, mp->conn_s);
-    if (items_written < 1) {
-        LOG_FATALF("fwrite failed to write msg %zu", items_written);
+        // const size_t msg_len = PADDLE_CHANGE_DIR_MSG_ENCODED_SIZE;
+        // if (fwrite(&msg_len, sizeof(size_t), 1, mp->conn_s) < 1) {
+        //     LOG_FATAL("Failed to write msg_len");
+        // }
+        // if (fwrite(&msg.dir, sizeof(msg.dir), 1, mp->conn_s) < 1) {
+        //     LOG_FATAL("Failed to write msg");
+        // }
+        // if (fflush(mp->conn_s) != 0) {
+        //     LOG_FATAL("Failed to flush stream");
+        // }
     }
-    if (fflush(mp->conn_s) == EOF) {
-        LOG_FATAL("fflush failed at msg");
-    }
-    printf("Sent %zu items\n", items_written);
-
-    // ssize_t res = send(mp->sock, buf, strlen(buf) - 1, 0);
-    // if (res == -1) {
-    //     LOG_ERRORF("send failed: %d %s", errno, strerror(errno));
-    //     return;
-    // }
-    // printf("Sent %zu bytes\n", res);
+
+    // last_dir = new_direction;
+
+    GameState_update(&mp->state, delta);
 }

+ 4 - 1
src/game/MultiPlayer.h

@@ -3,7 +3,10 @@
 #include <stdint.h>
 #include <stdio.h>
 
+#include "game.h"
+
 typedef struct {
+    GameState state;
     int sock;
     int conn;
     FILE *conn_s;
@@ -14,4 +17,4 @@ MultiPlayer MultiPlayer_alloc(
     const uint16_t server_port
 );
 void MultiPlayer_free(MultiPlayer *const mp);
-void MultiPlayer_tick(MultiPlayer *const mp);
+void MultiPlayer_tick(MultiPlayer *const mp, const double delta);

+ 40 - 16
src/game/SinglePlayer.c

@@ -1,4 +1,5 @@
 #include "cglm/vec4.h"
+#include "game.h"
 #include "scufeng/Scene.h"
 
 #include "SinglePlayer.h"
@@ -7,30 +8,53 @@
 SinglePlayer SinglePlayer_alloc(
     unsigned int screen_w,
     unsigned int screen_h,
-    float paddles_w,
-    float paddles_h,
-    float paddle_l_x,
-    float paddle_speed,
-    float ball_w,
-    vec2 ball_pos,
-    float ball_speed
+    GameStateParameters params
 ) {
     SinglePlayer sp = {
         .screen_w = screen_w,
         .screen_h = screen_h,
-        .state = GameState_new(
-            paddles_w,
-            paddles_h,
-            paddle_l_x,
-            paddle_speed,
-            ball_w,
-            ball_pos,
-            ball_speed
-        ),
+        .state = GameState_new(params),
         .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),
     };
+    sp.paddle_l.transform.scale[0] = screen_w * params.paddles_w;
+    sp.paddle_l.transform.scale[1] = screen_h * params.paddles_h;
+    sp.paddle_l.transform.pos[0] = screen_w * params.paddle_l_x;
+    sp.paddle_l.transform.pos[1] = screen_h / 2.0f;
+
+    sp.paddle_r.transform.scale[0] = screen_w * params.paddles_w;
+    sp.paddle_r.transform.scale[1] = screen_h * params.paddles_h;
+    sp.paddle_r.transform.pos[0] = screen_w * (1.0f - params.paddle_l_x);
+    sp.paddle_r.transform.pos[1] = screen_h / 2.0f;
+
+    sp.ball.transform.scale[0] = screen_w * params.ball_w;
+    sp.ball.transform.scale[1] = sp.ball.transform.scale[0];
+    sp.ball.transform.pos[0] = screen_w * params.ball_pos[0];
+    sp.ball.transform.pos[1] = screen_h * params.ball_pos[1];
+
+    return sp;
+}
+
+SinglePlayer SinglePlayer_alloc_default(
+    unsigned int screen_w,
+    unsigned int screen_h
+) {
+    SinglePlayer sp = {
+        .screen_w = screen_w,
+        .screen_h = screen_h,
+        .state = GameState_new(game_default_params),
+        .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),
+    };
+
+    const float paddles_w = game_default_params.paddles_w;
+    const float paddles_h = game_default_params.paddles_h;
+    const float paddle_l_x = game_default_params.paddle_l_x;
+    const float ball_w = game_default_params.ball_w;
+    const float *ball_pos = game_default_params.ball_pos; // Scuffed but here for conveniance for now
+
     sp.paddle_l.transform.scale[0] = screen_w * paddles_w;
     sp.paddle_l.transform.scale[1] = screen_h * paddles_h;
     sp.paddle_l.transform.pos[0] = screen_w * paddle_l_x;

+ 5 - 7
src/game/SinglePlayer.h

@@ -17,13 +17,11 @@ typedef struct {
 SinglePlayer SinglePlayer_alloc(
     unsigned int screen_w,
     unsigned int screen_h,
-    float paddles_w,
-    float paddles_h,
-    float paddle_l_x,
-    float paddle_speed,
-    float ball_w,
-    vec2 ball_pos,
-    float ball_speed
+    GameStateParameters params
+);
+SinglePlayer SinglePlayer_alloc_default(
+    unsigned int screen_w,
+    unsigned int screen_h
 );
 void SinglePlayer_free(SinglePlayer *sp);
 Screen SinglePlayer_tick(SinglePlayer *const sp, const double delta);

+ 10 - 17
src/game/pong.c

@@ -9,13 +9,13 @@
 
 static const unsigned int screen_w = 1200;
 static const unsigned int screen_h = 600;
-static const float paddles_w = 0.01f;
-static const float paddles_h = 0.10f;
-static const float paddle_l_x = (1.0f / 16);
-static const float ball_w = paddles_w * 0.5f;
-static vec2 ball_pos = { 0.5f, 0.5f };
-static const float paddle_speed = 0.7f;
-static const float ball_speed = 0.7f;
+// static const float paddles_w = 0.01f;
+// static const float paddles_h = 0.10f;
+// static const float paddle_l_x = (1.0f / 16);
+// static const float ball_w = paddles_w * 0.5f;
+// static vec2 ball_pos = { 0.5f, 0.5f };
+// static const float paddle_speed = 0.7f;
+// static const float ball_speed = 0.7f;
 
 int main() {
     se_init(true);
@@ -45,16 +45,9 @@ int main() {
             current_screen = MainMenu_tick(&mm);
             switch (current_screen) {
             case PONG_SINGLEPLAYER:
-                sp = SinglePlayer_alloc(
+                sp = SinglePlayer_alloc_default(
                     screen_w,
-                    screen_h,
-                    paddles_w,
-                    paddles_h,
-                    paddle_l_x,
-                    paddle_speed,
-                    ball_w,
-                    ball_pos,
-                    ball_speed
+                    screen_h
                 );
                 break;
             case PONG_MULTIPLAYER:
@@ -72,7 +65,7 @@ int main() {
             break;
 
         case PONG_MULTIPLAYER:
-            MultiPlayer_tick(&mp);
+            MultiPlayer_tick(&mp, delta);
             break;
         }
 

+ 147 - 34
src/server/server.c

@@ -6,13 +6,113 @@
 #include <errno.h>
 #include <arpa/inet.h>
 #include <unistd.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
 
+#include "scufeng/engine.h"
 #include "scufeng/log.h"
+#include "game.h"
+#include "networking.h"
 
 #define SERVER_HOST "127.0.0.1"
 #define SERVER_PORT 8080
 
+typedef enum {
+    SS_LOBBY,
+    SS_GAME
+} ServerState;
+
+static FILE *p1_conn = nullptr;
+static FILE *p2_conn = nullptr;
+
+static ServerState server_state = SS_LOBBY;
+
+static void server_lobby(const int sock) {
+    int player1 = accept(sock, nullptr, nullptr);
+    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));
+    // }
+    printf("Player 1 connected\n");
+
+    p1_conn = fdopen(player1, "r+");
+    if (p1_conn == nullptr) {
+        LOG_FATAL("fdoepn failed for p1");
+    }
+
+    // int player2 = accept(sock, nullptr, nullptr);
+    // if (player2 == -1) {
+    //     LOG_FATALF("accept failed: %s", strerror(errno));
+    // }
+    // if (fcntl(player2, F_SETFL, O_NONBLOCK) != 0) {
+    //     LOG_FATALF("fcntl failed on player2: (%d) %s", errno, strerror(errno));
+    // }
+    // printf("Player 2 connected\n");
+
+    // p2_conn = fdopen(player2, "r+");
+    // if (p2_conn == nullptr) {
+    //     LOG_FATAL("fdoepn failed for p2");
+    // }
+}
+
+static void server_game() {
+    GameState state = GameState_new(game_default_params);
+
+    se_fps_lock_set_fps(60);
+
+    double last_frame_time_s = 0.0;
+    while (true) {
+        const double current_time_s = se_get_time();
+        const double delta = current_time_s - last_frame_time_s;
+        se_fps_lock_frame_start_s(current_time_s);
+
+        // Player input
+        // size_t msg_len;
+        // if (fread(&msg_len, sizeof(msg_len), 1, p1_conn) < 1) {
+        //     printf("feof: %d ferror: %d errno: %d\n", feof(p1_conn), ferror(p1_conn), errno);
+        //     LOG_FATAL("Failed to read msg_len from p1_conn");
+        // }
+        // printf("msg_len: %zu\n", msg_len);
+        //
+        // uint8_t *buf = (uint8_t *) malloc(msg_len);
+        // if (fread(buf, msg_len, 1, p1_conn) < 1) {
+        //     printf("feof: %d ferror: %d errno: %d\n", feof(p1_conn), ferror(p1_conn), errno);
+        //     LOG_FATAL("Failed to read msg from p1_conn");
+        // }
+        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");
+        }
+
+        // free(buf);
+        // buf = nullptr;
+
+        // Tick
+        GameState_update(&state, delta);
+
+        // Player output
+
+        // Wait
+        se_fps_lock_wait();
+    }
+}
+
 int main() {
+    se_init(true);
+
     struct protoent *proto = getprotobyname("tcp");
     if (proto == nullptr) {
         LOG_FATAL("getprotobyname failed");
@@ -21,6 +121,13 @@ int main() {
     if (sock == -1) {
         LOG_FATALF("socket failed: %s", strerror(errno));
     }
+    {
+        int val = 1;
+        val = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+        if (val != 0) {
+            LOG_FATALF("setsockopt failed: (%d) %s", errno, strerror(errno));
+        }
+    }
 
     {
         struct in_addr addr;
@@ -44,43 +151,50 @@ int main() {
         LOG_FATALF("listen failed: %s", strerror(errno));
     }
 
-    int conn = accept(sock, nullptr, nullptr);
-    if (conn == -1) {
-        LOG_FATALF("accept failed: %s", strerror(errno));
-    }
-
-    printf("Player connected\n");
-
-    FILE *conn_s = fdopen(conn, "r+");
-    if (conn_s == nullptr) {
-        LOG_FATALF("fdopen failed: (%d) %s", errno, strerror(errno));
-    }
-
     while (true) {
-        printf("Reading msg_len\n");
-        size_t msg_len;
-        size_t bytes_read = fread(&msg_len, sizeof(msg_len), 1, conn_s);
-        if (bytes_read < 1) {
-            LOG_FATALF("fread failed to read msg_len %zu", bytes_read);
+        switch (server_state) {
+        case SS_LOBBY:
+            server_lobby(sock);
+            server_state = SS_GAME;
+            break;
+        case SS_GAME:
+            server_game();
+            break;
         }
-        printf("msg_len: %zu\n", msg_len);
-
-        printf("\nReading msg\n");
-        char *msg = (char *) malloc(msg_len + 1);
-        bytes_read = fread(msg, msg_len, 1, conn_s);
-        if (bytes_read < 1) {
-            LOG_FATALF("fread failed to read msg %zu", bytes_read);
-        }
-        msg[msg_len] = '\0';
-
-        printf("msg: %s\n\n", msg);
-
-        free(msg);
     }
 
-    fclose(conn_s);
-    close(conn);
-    close(sock);
+    // printf("Player connected\n");
+    //
+    // FILE *conn_s = fdopen(conn, "r+");
+    // if (conn_s == nullptr) {
+    //     LOG_FATALF("fdopen failed: (%d) %s", errno, strerror(errno));
+    // }
+    //
+    // while (true) {
+    //     printf("Reading msg_len\n");
+    //     size_t msg_len;
+    //     size_t bytes_read = fread(&msg_len, sizeof(msg_len), 1, conn_s);
+    //     if (bytes_read < 1) {
+    //         LOG_FATALF("fread failed to read msg_len %zu", bytes_read);
+    //     }
+    //     printf("msg_len: %zu\n", msg_len);
+    //
+    //     printf("\nReading msg\n");
+    //     char *msg = (char *) malloc(msg_len + 1);
+    //     bytes_read = fread(msg, msg_len, 1, conn_s);
+    //     if (bytes_read < 1) {
+    //         LOG_FATALF("fread failed to read msg %zu", bytes_read);
+    //     }
+    //     msg[msg_len] = '\0';
+    //
+    //     printf("msg: %s\n\n", msg);
+    //
+    //     free(msg);
+    // }
+    //
+    // fclose(conn_s);
+    // close(conn);
+    // close(sock);
 
     // char inter_buf[1024] = {0};
     // const size_t inter_buf_size = sizeof(inter_buf) / sizeof(inter_buf[0]);
@@ -131,6 +245,5 @@ int main() {
     //     // printf("loop buf: %s\n", buf);
     // }
 
-
     return 0;
 }