Add support for marshalling GameState + packed values
authorThomas Perl <thp@thpinfo.com>
Tue, 4 Aug 2009 19:00:06 +0000 (4 21:00 +0200)
committerThomas Perl <thp@thpinfo.com>
Tue, 4 Aug 2009 19:00:06 +0000 (4 21:00 +0200)
game.c
game.h
makefile
network.c [new file with mode: 0644]
network.h [new file with mode: 0644]

diff --git a/game.c b/game.c
index b05b0ca..cd816ab 100644 (file)
--- a/game.c
+++ b/game.c
@@ -33,6 +33,7 @@
 #include "input.h"
 #include "sound.h"
 #include "util.h"
+#include "network.h"
 
 
 GameState *gamestate_new() {
@@ -41,10 +42,10 @@ GameState *gamestate_new() {
     GameState template = {
         NULL,
         -1,
-        { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.6, false, -1, false },
+        { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false, -1, false },
         {
-            { NULL, -1, GAME_X_MIN-RACKET_X_MID*2, GAME_Y_MID, 0.0, POWER_UP_FACTOR, POWER_DOWN_FACTOR, true, 0, DESIRE_NORMAL, PLAYER_TYPE_AI, 0, {0}, PLAYER_ACCEL_DEFAULT },
-            { NULL, -1, GAME_X_MAX+RACKET_X_MID*2, GAME_Y_MID, 0.0, POWER_UP_FACTOR, POWER_DOWN_FACTOR, true, 0, DESIRE_NORMAL, PLAYER_TYPE_AI, 0, {0}, PLAYER_ACCEL_DEFAULT },
+            { NULL, -1, GAME_X_MIN-RACKET_X_MID*2, GAME_Y_MID, 0.0, true, 0, DESIRE_NORMAL, PLAYER_TYPE_AI, 0, {0}, PLAYER_ACCEL_DEFAULT },
+            { NULL, -1, GAME_X_MAX+RACKET_X_MID*2, GAME_Y_MID, 0.0, true, 0, DESIRE_NORMAL, PLAYER_TYPE_AI, 0, {0}, PLAYER_ACCEL_DEFAULT },
         },
         1,
         REFEREE_NORMAL,
@@ -240,6 +241,9 @@ void gameloop(GameState *s) {
 void step(GameState* s) {
     bool ground_event = false;
     int p;
+    fprintf(stderr, "ball(%f, %f, %f, %f, %f, %f)\n",
+            s->ball.x, s->ball.y, s->ball.z,
+            s->ball.move_x, s->ball.move_y, s->ball.move_z);
 
     s->ball.z += s->ball.move_z;
     if (!s->ball.inhibit_gravity) {
@@ -252,7 +256,7 @@ void step(GameState* s) {
     for (p=1; p<=MAXPLAYERS; p++) {
         if (PLAYER(s, p).use_power) {
             PLAYER(s, p).power = fmaxf(0.0, fminf(
-                        PLAYER(s, p).power*PLAYER(s, p).power_down_factor,
+                        PLAYER(s, p).power*POWER_DOWN_FACTOR,
                         PLAYER_POWER_MAX));
         }
     }
@@ -266,7 +270,7 @@ void step(GameState* s) {
         /* bounce from the ground */
         if (fabsf(s->ball.move_z) > 0.3) {
             s->sound_events ^= SOUND_EVENT_GROUND;
-            s->ball.move_z *= -s->ball.restitution;
+            s->ball.move_z *= -BALL_RESTITUTION;
         } else {
             s->ball.move_z = 0;
         }
@@ -393,7 +397,7 @@ void step(GameState* s) {
 }
 
 bool handle_input(GameState* s) {
-    static GameState tmp;
+    static NetworkGameState tmp;
     Uint8* keys = NULL;
     int p;
 
@@ -401,9 +405,9 @@ bool handle_input(GameState* s) {
     keys = SDL_GetKeyState(NULL);
 
     if (keys['1']) {
-        memcpy(&tmp, s, sizeof(GameState));
+        net_serialize_gamestate(s, &tmp);
     } else if (keys['2']) {
-        memcpy(s, &tmp, sizeof(GameState));
+        net_unserialize_gamestate(&tmp, s);
     }
 
     if (s->winner == WINNER_NONE) {
@@ -682,7 +686,7 @@ void input_human(GameState* s, int player) {
         PLAYER(s, player).desire = (topspin)?(DESIRE_TOPSPIN):(DESIRE_NORMAL);
         PLAYER(s, player).desire = (smash)?(DESIRE_SMASH):(PLAYER(s, player).desire);
 
-        PLAYER(s, player).power = fmaxf(10.0, fminf(PLAYER(s, player).power*PLAYER(s, player).power_up_factor, PLAYER_POWER_MAX));
+        PLAYER(s, player).power = fmaxf(10.0, fminf(PLAYER(s, player).power*POWER_UP_FACTOR, PLAYER_POWER_MAX));
         PLAYER(s, player).use_power = false;
     } else {
         PLAYER(s, player).use_power = true;
@@ -716,7 +720,7 @@ void input_ai(GameState* s, int player) {
         if (IS_NEAR_Y(PLAYER(s, player).y, (s->ball.y-s->ball.z)) && IS_NEAR_X_AI(PLAYER(s, player).x, s->ball.x) && PLAYER(s, player).power > 90.) {
             PLAYER(s, player).use_power = true;
         } else if (ball_approaching) {
-            PLAYER(s, player).power = fmaxf(10., fminf(PLAYER(s, player).power*PLAYER(s, player).power_up_factor, PLAYER_POWER_MAX));
+            PLAYER(s, player).power = fmaxf(10., fminf(PLAYER(s, player).power*POWER_UP_FACTOR, PLAYER_POWER_MAX));
             PLAYER(s, player).use_power = false;
         }
     }
diff --git a/game.h b/game.h
index 4983431..b76a36d 100644 (file)
--- a/game.h
+++ b/game.h
@@ -89,6 +89,8 @@ typedef struct {
     unsigned int fog;
 } Location;
 
+#define BALL_RESTITUTION .6
+
 typedef struct {
     float x;
     float y;
@@ -96,26 +98,23 @@ typedef struct {
     float move_x;
     float move_y;
     float move_z;
-    float restitution;
     bool ground_hit;
-    int last_hit_by;
+    char last_hit_by;
     bool inhibit_gravity;
 } Ball;
 
 typedef struct {
     InputDevice* input;
-    int input_device_index;
+    char input_device_index;
     float x;
     float y;
     float power;
-    float power_up_factor;
-    float power_down_factor;
     bool use_power;
-    unsigned int score;
+    unsigned char score;
     unsigned char desire;
     bool type; /* is this player ai-controlled or human? */
-    int game; /* score for the current game */
-    int sets[SETS_TO_WIN*2]; /* score for each set */
+    char game; /* score for the current game */
+    unsigned char sets[SETS_TO_WIN*2]; /* score for each set */
     float accelerate; /* a value [0..1] how fast the user accelerates */
 } Player;
 
index 7830eb3..da8e79c 100644 (file)
--- a/makefile
+++ b/makefile
@@ -73,8 +73,8 @@ else
   CFLAGS += $$(sdl-config --cflags)
 endif
 
-SRC = tennix.c game.c graphics.c input.c util.c sound.c animation.c
-OBJ = tennix.o game.o graphics.o input.o util.o sound.o animation.o archive-lib.o SDL_rotozoom.o
+SRC = tennix.c game.c graphics.c input.c util.c sound.c animation.c network.c
+OBJ = tennix.o game.o graphics.o input.o util.o sound.o animation.o archive-lib.o SDL_rotozoom.o network.o
 ifeq ($(MSYSTEM),MINGW32)
   OBJ += tennixres.o
 endif
@@ -113,12 +113,13 @@ install: tennix
 
 tennix.o: tennix.c tennix.h game.h graphics.h input.h util.h animation.h sound.h locations.h util.h
 graphics.o: graphics.c graphics.h tennix.h archive.h sound.h
-game.o: game.c game.h graphics.h tennix.h sound.h input.h util.h
+game.o: game.c game.h graphics.h tennix.h sound.h input.h util.h network.h
 sound.o: sound.c sound.h tennix.h archive.h graphics.h
 input.o: input.c input.h tennix.h graphics.h game.h util.h tennixpy.h
 util.o: util.c util.h tennix.h
 animation.o: animation.c animation.h graphics.h tennix.h credits.h
 tennixpy.o: tennix.c tennix.h game.h archive.h
+network.o: network.c network.h game.h
 SDL_rotozoom.o: SDL_rotozoom.c SDL_rotozoom.h
 
 archive-lib.o: archive.c archive.h
diff --git a/network.c b/network.c
new file mode 100644 (file)
index 0000000..0b5f271
--- /dev/null
+++ b/network.c
@@ -0,0 +1,144 @@
+
+/**
+ *
+ * Tennix! SDL Port
+ * Copyright (C) 2003, 2007, 2008, 2009 Thomas Perl <thp@thpinfo.com>
+ * 
+ * This program 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 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
+ * MA  02110-1301, USA.
+ *
+ **/
+
+#include "game.h"
+#include "network.h"
+
+#include <assert.h>
+#include <SDL/SDL_net.h>
+
+/* HELPER FUNCTIONS */
+
+Uint32
+pack_float(float v, float min, float max)
+{
+    assert(v >= min && v < max);
+    return (Uint32)((1U<<31) * (v-min) / (max-min));
+}
+
+float
+unpack_float(Uint32 v, float min, float max)
+{
+    assert(v < (1U<<31));
+    return v * (max-min) / (1U<<31) + min;
+}
+
+
+void
+net_serialize_ball(const Ball* src, NetworkBall* dest)
+{
+    SDLNet_Write32(pack_float(src->x, -WIDTH, WIDTH), &(dest->x));
+    SDLNet_Write32(pack_float(src->y, -HEIGHT, HEIGHT), &(dest->y));
+    SDLNet_Write32(pack_float(src->z, -50, 50), &(dest->z));
+    SDLNet_Write32(pack_float(src->move_x, -50, 50), &(dest->move_x));
+    SDLNet_Write32(pack_float(src->move_y, -50, 50), &(dest->move_y));
+    SDLNet_Write32(pack_float(src->move_z, -50, 50), &(dest->move_z));
+    dest->ground_hit = src->ground_hit;
+    dest->last_hit_by = src->last_hit_by;
+    dest->inhibit_gravity = src->inhibit_gravity;
+}
+
+void
+net_unserialize_ball(const NetworkBall* src, Ball* dest)
+{
+    dest->x = unpack_float(SDLNet_Read32(&(src->x)), -WIDTH, WIDTH);
+    dest->y = unpack_float(SDLNet_Read32(&(src->y)), -HEIGHT, HEIGHT);
+    dest->z = unpack_float(SDLNet_Read32(&(src->z)), -50, 50);
+    dest->move_x = unpack_float(SDLNet_Read32(&(src->move_x)), -50, 50);
+    dest->move_y = unpack_float(SDLNet_Read32(&(src->move_y)), -50, 50);
+    dest->move_z = unpack_float(SDLNet_Read32(&(src->move_z)), -50, 50);
+    dest->ground_hit = src->ground_hit;
+    dest->last_hit_by = src->last_hit_by;
+    dest->inhibit_gravity = src->inhibit_gravity;
+}
+
+void
+net_serialize_player(const Player* src, NetworkPlayer* dest)
+{
+    SDLNet_Write32(pack_float(src->x, 0, WIDTH), &(dest->x));
+    SDLNet_Write32(pack_float(src->y, 0, HEIGHT), &(dest->y));
+    SDLNet_Write32(pack_float(src->power, 0, 110), &(dest->power));
+    dest->use_power = src->use_power;
+    dest->score = src->score;
+    dest->desire = src->desire;
+    dest->game = src->game;
+    memcpy(dest->sets, src->sets, sizeof(unsigned char)*(SETS_TO_WIN*2));
+    SDLNet_Write32(pack_float(src->accelerate, 0, 1), &(dest->accelerate));
+}
+
+void
+net_unserialize_player(const NetworkPlayer* src, Player* dest)
+{
+    dest->x = unpack_float(SDLNet_Read32(&(src->x)), 0, WIDTH);
+    dest->y = unpack_float(SDLNet_Read32(&(src->y)), 0, HEIGHT);
+    dest->power = unpack_float(SDLNet_Read32(&(src->power)), 0, 110);
+    dest->use_power = src->use_power;
+    dest->score = src->score;
+    dest->desire = src->desire;
+    dest->game = src->game;
+    memcpy(dest->sets, src->sets, sizeof(unsigned char)*(SETS_TO_WIN*2));
+    dest->accelerate = unpack_float(SDLNet_Read32(&(src->accelerate)), 0, 1);
+}
+
+void
+net_serialize_gamestate(const GameState* src, NetworkGameState* dest)
+{
+    int p;
+
+    net_serialize_ball(&(src->ball), &(dest->ball));
+    for (p=0; p<MAXPLAYERS; p++) {
+        net_serialize_player(&(src->players[p]), &(dest->players[p]));
+    }
+    dest->serving_player = src->serving_player;
+    dest->referee = src->referee;
+    dest->current_set = src->current_set;
+    dest->winner = src->winner;
+    dest->sound_events = src->sound_events;
+    dest->score_event = src->score_event;
+    dest->ec_game = src->ec_game;
+    dest->ec_sets = src->ec_sets;
+    dest->status_message = src->status_message;
+
+    fprintf(stderr, "size = %lu\n", sizeof(NetworkGameState));
+}
+
+void
+net_unserialize_gamestate(const NetworkGameState* src, GameState* dest)
+{
+    int p;
+
+    net_unserialize_ball(&(src->ball), &(dest->ball));
+    for (p=0; p<MAXPLAYERS; p++) {
+        net_unserialize_player(&(src->players[p]), &(dest->players[p]));
+    }
+    dest->serving_player = src->serving_player;
+    dest->referee = src->referee;
+    dest->current_set = src->current_set;
+    dest->winner = src->winner;
+    dest->sound_events = src->sound_events;
+    dest->score_event = src->score_event;
+    dest->ec_game = src->ec_game;
+    dest->ec_sets = src->ec_sets;
+    dest->status_message = src->status_message;
+}
+
diff --git a/network.h b/network.h
new file mode 100644 (file)
index 0000000..b5e0e9a
--- /dev/null
+++ b/network.h
@@ -0,0 +1,87 @@
+
+/**
+ *
+ * Tennix! SDL Port
+ * Copyright (C) 2003, 2007, 2008, 2009 Thomas Perl <thp@thpinfo.com>
+ * 
+ * This program 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 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
+ * MA  02110-1301, USA.
+ *
+ **/
+
+#ifndef __NETWORK_H
+#define __NETWORK_H
+
+#include "game.h"
+
+typedef struct {
+    Uint32 x;
+    Uint32 y;
+    Uint32 z;
+    Uint32 move_x;
+    Uint32 move_y;
+    Uint32 move_z;
+    bool ground_hit;
+    char last_hit_by;
+    bool inhibit_gravity;
+} NetworkBall;
+
+typedef struct {
+    Uint32 x;
+    Uint32 y;
+    Uint32 power;
+    bool use_power;
+    unsigned char score;
+    unsigned char desire;
+    char game; /* score for the current game */
+    unsigned char sets[SETS_TO_WIN*2]; /* score for each set */
+    Uint32 accelerate; /* a value [0..1] how fast the user accelerates */
+} NetworkPlayer;
+
+typedef struct {
+    NetworkBall ball;
+    NetworkPlayer players[MAXPLAYERS];
+    unsigned char serving_player;
+    referee_t referee;
+    unsigned char current_set;
+    winner_t winner;
+    soundevent_t sound_events;
+    scoreevent_t score_event;
+    unsigned char score_time;
+    eventcounter_t ec_game;
+    eventcounter_t ec_sets;
+    statusmessage_t status_message;
+} NetworkGameState;
+
+void
+net_serialize_ball(const Ball* src, NetworkBall* dest);
+
+void
+net_unserialize_ball(const NetworkBall* src, Ball* dest);
+
+void
+net_serialize_player(const Player* src, NetworkPlayer* dest);
+
+void
+net_unserialize_player(const NetworkPlayer* src, Player* dest);
+
+void
+net_serialize_gamestate(const GameState* src, NetworkGameState* dest);
+
+void
+net_unserialize_gamestate(const NetworkGameState* src, GameState* dest);
+
+#endif
+