1
0

MultiPlayer.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. #include <asm-generic/errno.h>
  2. #include <stdio.h>
  3. #include <sys/socket.h>
  4. #include <netdb.h>
  5. #include <errno.h>
  6. #include <string.h>
  7. #include <netinet/in.h>
  8. #include <arpa/inet.h>
  9. #include <unistd.h>
  10. #include <fcntl.h>
  11. #include "scufeng/log.h"
  12. #include "networking.h"
  13. #include "MultiPlayer.h"
  14. #include "game.h"
  15. #include "game_common.h"
  16. #include "GameState_net.h"
  17. static bool handle_game_state_msg(MultiPlayer *const mp) {
  18. GameStateMsg msg;
  19. if (!recv_msg(mp->conn_s, NET_MSG_GAME_STATE, (uint8_t *) &msg)) {
  20. return false;
  21. }
  22. GameStateMsg_to_GameState(&msg, &mp->state);
  23. return true;
  24. }
  25. bool MultiPlayer_alloc(
  26. MultiPlayer *const mp,
  27. const unsigned int screen_w,
  28. const unsigned int screen_h,
  29. const char *server_host,
  30. const uint16_t server_port
  31. ) {
  32. struct protoent *proto = getprotobyname("tcp");
  33. mp->sock = socket(AF_INET, SOCK_STREAM, proto->p_proto);
  34. if (mp->sock == -1) {
  35. SE_LOG_FATALF("socket failed: %d %s", errno, strerror(errno));
  36. }
  37. struct in_addr server_addr;
  38. int res = inet_aton(server_host, &server_addr);
  39. if (res == 0) {
  40. close(mp->sock);
  41. SE_LOG_FATAL("inet_aton failed");
  42. }
  43. struct sockaddr_in server_sockaddr = {
  44. .sin_family = AF_INET,
  45. .sin_addr = server_addr,
  46. .sin_port = htons(server_port)
  47. };
  48. res = connect(
  49. mp->sock,
  50. (struct sockaddr *) &server_sockaddr,
  51. sizeof(server_sockaddr)
  52. );
  53. if (res == -1) {
  54. close(mp->sock);
  55. SE_LOG_ERRORF("connect failed: %d %s", errno, strerror(errno));
  56. return false;
  57. }
  58. SE_LOG("Connected to server");
  59. mp->conn_s = fdopen(mp->sock, "r+");
  60. if (mp->conn_s == nullptr) {
  61. close(mp->sock);
  62. SE_LOG_ERRORF("fdopen failed: (%d) %s", errno, strerror(errno));
  63. return false;
  64. }
  65. NetMsgType msg_type;
  66. if (recv_msg_type(mp->conn_s, &msg_type) == ECONNRESET) {
  67. fclose(mp->conn_s);
  68. close(mp->sock);
  69. SE_LOG_ERROR("Connection reset");
  70. return false;
  71. }
  72. if (msg_type != NET_MSG_IS_PLAYER_1) {
  73. fclose(mp->conn_s);
  74. close(mp->sock);
  75. SE_LOG_ERRORF("Did not get IS_PLAYER_1 msg, got: %u", msg_type);
  76. return false;
  77. }
  78. IsPlayer1Msg p1_msg = { 0 };
  79. if (!recv_msg(mp->conn_s, NET_MSG_IS_PLAYER_1, (uint8_t *) &p1_msg)) {
  80. fclose(mp->conn_s);
  81. close(mp->sock);
  82. SE_LOG_ERROR("Connection reset");
  83. return false;
  84. }
  85. mp->is_player_1 = (bool) p1_msg.player1;
  86. if (mp->is_player_1) {
  87. SE_LOG("I am player 1");
  88. } else {
  89. SE_LOG("I am player 2");
  90. }
  91. SE_LOG("Waiting for game start");
  92. mp->state = GameState_new(game_default_params, false);
  93. if (recv_msg_type(mp->conn_s, &msg_type) == ECONNRESET) {
  94. fclose(mp->conn_s);
  95. close(mp->sock);
  96. SE_LOG_ERROR("Connection reset");
  97. return false;
  98. }
  99. if (msg_type != NET_MSG_GAME_STATE) {
  100. fclose(mp->conn_s);
  101. close(mp->sock);
  102. SE_LOG_FATALF("[MultiPlayer_alloc] Did not get GAME_STATE msg, got: %u", msg_type);
  103. }
  104. if (!handle_game_state_msg(mp)) {
  105. fclose(mp->conn_s);
  106. close(mp->sock);
  107. SE_LOG_ERROR("Connection reset");
  108. return false;
  109. }
  110. if (recv_msg_type(mp->conn_s, &msg_type) == ECONNRESET) {
  111. fclose(mp->conn_s);
  112. close(mp->sock);
  113. SE_LOG_ERROR("Connection reset");
  114. return false;
  115. }
  116. if (msg_type != NET_MSG_GAME_START) {
  117. fclose(mp->conn_s);
  118. close(mp->sock);
  119. SE_LOG_FATALF("[MultiPlayer_alloc] Did not get GAME_START msg, got: %u", msg_type);
  120. }
  121. if (!send_msg(mp->conn_s, NET_MSG_GAME_START, nullptr)) {
  122. fclose(mp->conn_s);
  123. close(mp->sock);
  124. SE_LOG_ERROR("Connection reset");
  125. return false;
  126. }
  127. if (fcntl(mp->sock, F_SETFL, O_NONBLOCK) != 0) {
  128. fclose(mp->conn_s);
  129. close(mp->sock);
  130. SE_LOG_ERRORF("fcntl failed on mp->sock: (%d) %s", errno, strerror(errno));
  131. return false;
  132. }
  133. SE_LOG("Game started");
  134. mp->screen_w = screen_w;
  135. mp->screen_h = screen_h;
  136. mp->shapes = GameShapes_alloc(screen_w, screen_h, game_default_params);
  137. return mp;
  138. }
  139. void MultiPlayer_free(MultiPlayer *const mp) {
  140. fclose(mp->conn_s);
  141. mp->conn_s = nullptr;
  142. // close(mp->conn);
  143. // mp->conn = 0;
  144. close(mp->sock);
  145. mp->sock = 0;
  146. GameShapes_free(&mp->shapes);
  147. }
  148. static void handle_paddle_pos_msg(MultiPlayer *const mp) {
  149. PaddleUpdateMsg msg;
  150. recv_msg(mp->conn_s, NET_MSG_PADDLE_POS, (uint8_t *) &msg);
  151. mp->state.paddle_l.pos[1] = msg.l_pos_y;
  152. mp->state.paddle_l.dirv[1] = msg.l_dirv_y;
  153. mp->state.paddle_r.pos[1] = msg.r_pos_y;
  154. mp->state.paddle_r.dirv[1] = msg.r_dirv_y;
  155. }
  156. static void handle_ball_update_msg(MultiPlayer *const mp) {
  157. BallUpdateMsg msg;
  158. recv_msg(mp->conn_s, NET_MSG_BALL_UPDATE, (uint8_t *) &msg);
  159. mp->state.ball.pos[0] = msg.ball_pos_x;
  160. mp->state.ball.pos[1] = msg.ball_pos_y;
  161. mp->state.ball.dirv[0] = msg.ball_dirv_x;
  162. mp->state.ball.dirv[1] = msg.ball_dirv_y;
  163. }
  164. static void handle_score_update_msg(MultiPlayer *const mp) {
  165. ScoreUpdateMsg msg;
  166. recv_msg(mp->conn_s, NET_MSG_SCORE_UPDATE, (uint8_t *) &msg);
  167. mp->state.score_l = msg.l_score;
  168. mp->state.score_r = msg.r_score;
  169. SE_LOGF("score_l: %d score_r: %d", mp->state.score_l, mp->state.score_r);
  170. }
  171. static void handle_input(
  172. const MultiPlayer *const mp,
  173. bool *dir_changed,
  174. SEDirection *new_dir,
  175. bool *quit
  176. ) {
  177. if (se_get_key(SE_KEY_ESCAPE) == SE_KEY_ACTION_PRESS) {
  178. *quit = true;
  179. return;
  180. }
  181. *new_dir = SE_NONE;
  182. *dir_changed = false;
  183. const SEDirection current_dir = GameState_paddle_l_dir_get(&mp->state);
  184. if (se_get_key(SE_KEY_W) == SE_KEY_ACTION_PRESS) {
  185. if (current_dir != SE_UP) {
  186. *new_dir = SE_UP;
  187. *dir_changed = true;
  188. }
  189. } else if (se_get_key(SE_KEY_S) == SE_KEY_ACTION_PRESS) {
  190. if (current_dir != SE_DOWN) {
  191. *new_dir = SE_DOWN;
  192. *dir_changed = true;
  193. }
  194. } else if (current_dir != SE_NONE) {
  195. *new_dir = SE_NONE;
  196. *dir_changed = true;
  197. }
  198. }
  199. Screen MultiPlayer_tick(MultiPlayer *const mp, const double delta) {
  200. NetMsgType msg_type;
  201. while (true) {
  202. const int res = recv_msg_type(mp->conn_s, &msg_type);
  203. if (res == 0) {
  204. switch (msg_type) {
  205. case NET_MSG_PADDLE_CHANGE_DIR:
  206. break;
  207. case NET_MSG_PADDLE_POS:
  208. handle_paddle_pos_msg(mp);
  209. break;
  210. case NET_MSG_GAME_STATE:
  211. handle_game_state_msg(mp);
  212. break;
  213. case NET_MSG_IS_PLAYER_1:
  214. case NET_MSG_GAME_START:
  215. break;
  216. case NET_MSG_BALL_UPDATE:
  217. handle_ball_update_msg(mp);
  218. break;
  219. case NET_MSG_SCORE_UPDATE:
  220. handle_score_update_msg(mp);
  221. break;
  222. }
  223. break;
  224. } else if (res == ECONNRESET) {
  225. SE_LOG_ERROR("Connection reset");
  226. return PONG_MAIN_MENU;
  227. } else if (res == EWOULDBLOCK) {
  228. break;
  229. } else {
  230. SE_LOG_FATALF("[MultiPlayer_tick] Unhandled return value: %d", res);
  231. }
  232. // SE_LOGF("Got message: %s", NetMsgType_to_str(msg_type));
  233. }
  234. bool dir_changed = false;
  235. SEDirection new_dir;
  236. bool quit = false;
  237. handle_input(mp, &dir_changed, &new_dir, &quit);
  238. if (quit) {
  239. return PONG_MAIN_MENU;
  240. }
  241. if (dir_changed) {
  242. GameState_paddle_l_change_dir(&mp->state, new_dir);
  243. const PaddleChangeDirMsg msg = {
  244. .dir = (uint8_t) new_dir
  245. };
  246. if (!send_msg(mp->conn_s, NET_MSG_PADDLE_CHANGE_DIR, (uint8_t *) &msg)) {
  247. SE_LOG_ERROR("Connection reset");
  248. return PONG_MAIN_MENU;
  249. }
  250. }
  251. GameState_update(&mp->state, delta);
  252. GameShapes_update(&mp->shapes, &mp->state, mp->screen_w, mp->screen_h);
  253. GameShapes_render(&mp->shapes, &mp->state, mp->screen_w, mp->screen_h);
  254. return PONG_MULTIPLAYER;
  255. }