84df73af12b2ca8677b8800b958cc0b9ca964d66
[tennix.git] / network.c
blob84df73af12b2ca8677b8800b958cc0b9ca964d66
2 /**
4 * Tennix! SDL Port
5 * Copyright (C) 2003, 2007, 2008, 2009 Thomas Perl <thp@thpinfo.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
22 **/
24 #include "game.h"
25 #include "network.h"
27 #include <assert.h>
28 #include <SDL/SDL_net.h>
30 /* HELPER FUNCTIONS */
32 Uint32
33 pack_float(float v, float min, float max)
35 assert(v >= min && v < max);
36 return (Uint32)((1U<<31) * (v-min) / (max-min));
39 float
40 unpack_float(Uint32 v, float min, float max)
42 assert(v < (1U<<31));
43 return v * (max-min) / (1U<<31) + min;
46 void
47 init_network()
49 SDLNet_Init();
52 void
53 uninit_network()
55 SDLNet_Quit();
58 TennixNet*
59 network_connect(const char* host, Uint16 local_port, Uint16 remote_port)
61 TennixNet* connection = (TennixNet*)malloc(sizeof(TennixNet));
62 assert(connection != NULL);
64 fprintf(stderr, "ports: %d and %d\n", local_port, remote_port);
66 assert(SDLNet_ResolveHost(&(connection->peer), (const char*)host, 0) == 0);
67 connection->base_port_local = local_port;
68 connection->base_port_remote = remote_port;
69 connection->input_packet = SDLNet_AllocPacket(sizeof(NetworkInputData));
70 connection->state_packet = SDLNet_AllocPacket(sizeof(NetworkGameState));
71 connection->input_available = false;
72 connection->state_available = false;
73 connection->send_input_socket = SDLNet_UDP_Open(0);
74 connection->send_state_socket = SDLNet_UDP_Open(0);
75 connection->recv_input_socket = SDLNet_UDP_Open(connection->base_port_local);
76 connection->recv_state_socket = SDLNet_UDP_Open(connection->base_port_local+1);
77 connection->master = false;
79 return connection;
82 void
83 network_disconnect(TennixNet* connection)
85 if (connection != NULL)
87 SDLNet_UDP_Close(connection->send_input_socket);
88 SDLNet_UDP_Close(connection->send_state_socket);
89 SDLNet_UDP_Close(connection->recv_input_socket);
90 SDLNet_UDP_Close(connection->recv_state_socket);
91 SDLNet_FreePacket(connection->input_packet);
92 SDLNet_FreePacket(connection->state_packet);
93 free(connection);
97 void
98 network_set_master(TennixNet* connection, bool master)
100 connection->master = master;
103 void
104 network_send_input(TennixNet* connection, NetworkInputData* src)
106 memcpy(connection->input_packet->data, src, sizeof(NetworkInputData));
107 connection->input_packet->address.host = connection->peer.host;
108 SDLNet_Write16(connection->base_port_remote, &(connection->input_packet->address.port));
109 connection->input_packet->channel = -1;
110 connection->input_packet->len = sizeof(NetworkInputData);
111 SDLNet_UDP_Send(connection->send_input_socket, -1, connection->input_packet);
114 void
115 network_send_state(TennixNet* connection, GameState* src)
117 if (connection->master) {
118 net_serialize_gamestate(src, (NetworkGameState*)(connection->state_packet->data));
119 connection->state_packet->address.host = connection->peer.host;
120 SDLNet_Write16(connection->base_port_remote+1, &(connection->state_packet->address.port));
121 connection->state_packet->channel = -1;
122 connection->state_packet->len = sizeof(NetworkGameState);
123 assert(SDLNet_UDP_Send(connection->send_state_socket, -1, connection->state_packet)!=0);
127 void
128 network_receive(TennixNet* connection)
130 connection->input_packet->len = sizeof(NetworkInputData);
131 while (SDLNet_UDP_Recv(connection->recv_input_socket, connection->input_packet)) {
132 connection->input_available = true;
135 if (!(connection->master)) {
136 connection->state_packet->len = sizeof(NetworkGameState);
137 while (SDLNet_UDP_Recv(connection->recv_state_socket, connection->state_packet)) {
138 connection->state_available = true;
143 void
144 network_get_input(TennixNet* connection, NetworkInputData* dest)
146 if (connection->input_available) {
147 memcpy(dest, connection->input_packet->data, sizeof(NetworkInputData));
148 connection->input_available = false;
152 void
153 network_get_gamestate(TennixNet* connection, GameState* dest)
155 if (connection->state_available) {
156 net_unserialize_gamestate((NetworkGameState*)
157 (connection->state_packet->data), dest);
158 connection->state_available = false;
163 void
164 net_serialize_ball(const Ball* src, NetworkBall* dest)
166 SDLNet_Write32(pack_float(src->x, -WIDTH, WIDTH*2), &(dest->x));
167 SDLNet_Write32(pack_float(src->y, -HEIGHT, HEIGHT*2), &(dest->y));
168 SDLNet_Write32(pack_float(src->z, -50, 50), &(dest->z));
169 SDLNet_Write32(pack_float(src->move_x, -50, 50), &(dest->move_x));
170 SDLNet_Write32(pack_float(src->move_y, -50, 50), &(dest->move_y));
171 SDLNet_Write32(pack_float(src->move_z, -50, 50), &(dest->move_z));
172 dest->ground_hit = src->ground_hit;
173 dest->last_hit_by = src->last_hit_by;
174 dest->inhibit_gravity = src->inhibit_gravity;
177 void
178 net_unserialize_ball(const NetworkBall* src, Ball* dest)
180 dest->x = unpack_float(SDLNet_Read32(&(src->x)), -WIDTH, WIDTH*2);
181 dest->y = unpack_float(SDLNet_Read32(&(src->y)), -HEIGHT, HEIGHT*2);
182 dest->z = unpack_float(SDLNet_Read32(&(src->z)), -50, 50);
183 dest->move_x = unpack_float(SDLNet_Read32(&(src->move_x)), -50, 50);
184 dest->move_y = unpack_float(SDLNet_Read32(&(src->move_y)), -50, 50);
185 dest->move_z = unpack_float(SDLNet_Read32(&(src->move_z)), -50, 50);
186 dest->ground_hit = src->ground_hit;
187 dest->last_hit_by = src->last_hit_by;
188 dest->inhibit_gravity = src->inhibit_gravity;
191 void
192 net_serialize_player(const Player* src, NetworkPlayer* dest)
194 SDLNet_Write32(pack_float(src->x, 0, WIDTH*1.2), &(dest->x));
195 SDLNet_Write32(pack_float(src->y, 0, HEIGHT*1.2), &(dest->y));
196 SDLNet_Write32(pack_float(src->power, 0, 110), &(dest->power));
197 dest->use_power = src->use_power;
198 dest->score = src->score;
199 dest->desire = src->desire;
200 dest->game = src->game;
201 memcpy(dest->sets, src->sets, sizeof(unsigned char)*(SETS_TO_WIN*2));
202 SDLNet_Write32(pack_float(src->accelerate, 0, 200), &(dest->accelerate));
205 void
206 net_unserialize_player(const NetworkPlayer* src, Player* dest)
208 dest->x = unpack_float(SDLNet_Read32(&(src->x)), 0, WIDTH*1.2);
209 dest->y = unpack_float(SDLNet_Read32(&(src->y)), 0, HEIGHT*1.2);
210 dest->power = unpack_float(SDLNet_Read32(&(src->power)), 0, 110);
211 dest->use_power = src->use_power;
212 dest->score = src->score;
213 dest->desire = src->desire;
214 dest->game = src->game;
215 memcpy(dest->sets, src->sets, sizeof(unsigned char)*(SETS_TO_WIN*2));
216 dest->accelerate = unpack_float(SDLNet_Read32(&(src->accelerate)), 0, 200);
219 void
220 net_serialize_gamestate(const GameState* src, NetworkGameState* dest)
222 int p;
224 net_serialize_ball(&(src->ball), &(dest->ball));
225 for (p=0; p<MAXPLAYERS; p++) {
226 net_serialize_player(&(src->players[p]), &(dest->players[p]));
228 dest->serving_player = src->serving_player;
229 dest->referee = src->referee;
230 dest->current_set = src->current_set;
231 dest->winner = src->winner;
232 dest->sound_events = src->sound_events;
233 dest->score_event = src->score_event;
234 dest->ec_game = src->ec_game;
235 dest->ec_sets = src->ec_sets;
236 dest->status_message = src->status_message;
238 fprintf(stderr, "size = %lu\n", sizeof(NetworkGameState));
241 void
242 net_unserialize_gamestate(const NetworkGameState* src, GameState* dest)
244 int p;
246 net_unserialize_ball(&(src->ball), &(dest->ball));
247 for (p=0; p<MAXPLAYERS; p++) {
248 net_unserialize_player(&(src->players[p]), &(dest->players[p]));
250 dest->serving_player = src->serving_player;
251 dest->referee = src->referee;
252 dest->current_set = src->current_set;
253 dest->winner = src->winner;
254 dest->sound_events = src->sound_events;
255 dest->score_event = src->score_event;
256 dest->ec_game = src->ec_game;
257 dest->ec_sets = src->ec_sets;
258 dest->status_message = src->status_message;