Only use one sending socket; auto-determine ports
[tennix.git] / network.c
blob444d6cde967bb4a66daab1522178b65eb7502f8c
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, bool master)
61 TennixNet* connection = (TennixNet*)malloc(sizeof(TennixNet));
62 assert(connection != NULL);
64 assert(SDLNet_ResolveHost(&(connection->peer), (const char*)host, 0) == 0);
65 connection->base_port_local = (master)?(TENNIXNET_PORT_MASTER):(TENNIXNET_PORT_SLAVE);
66 connection->base_port_remote = (master)?(TENNIXNET_PORT_SLAVE):(TENNIXNET_PORT_MASTER);
67 connection->input_packet = SDLNet_AllocPacket(sizeof(NetworkInputData));
68 connection->state_packet = SDLNet_AllocPacket(sizeof(NetworkGameState));
69 connection->input_available = false;
70 connection->state_available = false;
71 connection->send_socket = SDLNet_UDP_Open(0);
72 connection->recv_input_socket = SDLNet_UDP_Open(connection->base_port_local);
73 connection->recv_state_socket = SDLNet_UDP_Open(connection->base_port_local+1);
74 connection->master = master;
76 return connection;
79 void
80 network_disconnect(TennixNet* connection)
82 if (connection != NULL)
84 SDLNet_UDP_Close(connection->send_socket);
85 SDLNet_UDP_Close(connection->recv_input_socket);
86 SDLNet_UDP_Close(connection->recv_state_socket);
87 SDLNet_FreePacket(connection->input_packet);
88 SDLNet_FreePacket(connection->state_packet);
89 free(connection);
93 void
94 network_send_input(TennixNet* connection, NetworkInputData* src)
96 assert(src != NULL);
97 if (connection != NULL) {
98 memcpy(connection->input_packet->data, src, sizeof(NetworkInputData));
99 connection->input_packet->address.host = connection->peer.host;
100 SDLNet_Write16(connection->base_port_remote, &(connection->input_packet->address.port));
101 connection->input_packet->channel = -1;
102 connection->input_packet->len = sizeof(NetworkInputData);
103 SDLNet_UDP_Send(connection->send_socket, -1, connection->input_packet);
107 void
108 network_send_state(TennixNet* connection, GameState* src)
110 assert(src != NULL);
111 if (connection != NULL && connection->master) {
112 net_serialize_gamestate(src, (NetworkGameState*)(connection->state_packet->data));
113 connection->state_packet->address.host = connection->peer.host;
114 SDLNet_Write16(connection->base_port_remote+1, &(connection->state_packet->address.port));
115 connection->state_packet->channel = -1;
116 connection->state_packet->len = sizeof(NetworkGameState);
117 assert(SDLNet_UDP_Send(connection->send_socket, -1, connection->state_packet)!=0);
121 void
122 network_receive(TennixNet* connection)
124 if (connection != NULL) {
125 connection->input_packet->len = sizeof(NetworkInputData);
126 while (SDLNet_UDP_Recv(connection->recv_input_socket, connection->input_packet)) {
127 connection->input_available = true;
130 if (!(connection->master)) {
131 connection->state_packet->len = sizeof(NetworkGameState);
132 while (SDLNet_UDP_Recv(connection->recv_state_socket, connection->state_packet)) {
133 connection->state_available = true;
139 void
140 network_get_input(TennixNet* connection, NetworkInputData* dest)
142 assert(dest != NULL);
143 if (connection != NULL && connection->input_available) {
144 memcpy(dest, connection->input_packet->data, sizeof(NetworkInputData));
145 connection->input_available = false;
149 void
150 network_get_gamestate(TennixNet* connection, GameState* dest)
152 assert(dest != NULL);
153 if (connection != NULL && connection->state_available) {
154 net_unserialize_gamestate((NetworkGameState*)
155 (connection->state_packet->data), dest);
156 connection->state_available = false;
161 void
162 net_serialize_ball(const Ball* src, NetworkBall* dest)
164 assert(src != NULL && dest != NULL);
165 SDLNet_Write32(pack_float(src->x, -WIDTH, WIDTH*2), &(dest->x));
166 SDLNet_Write32(pack_float(src->y, -HEIGHT, HEIGHT*2), &(dest->y));
167 SDLNet_Write32(pack_float(src->z, -50, 50), &(dest->z));
168 SDLNet_Write32(pack_float(src->move_x, -50, 50), &(dest->move_x));
169 SDLNet_Write32(pack_float(src->move_y, -50, 50), &(dest->move_y));
170 SDLNet_Write32(pack_float(src->move_z, -50, 50), &(dest->move_z));
171 dest->ground_hit = src->ground_hit;
172 dest->last_hit_by = src->last_hit_by;
173 dest->inhibit_gravity = src->inhibit_gravity;
176 void
177 net_unserialize_ball(const NetworkBall* src, Ball* dest)
179 assert(src != NULL && dest != NULL);
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 assert(src != NULL && dest != NULL);
195 SDLNet_Write32(pack_float(src->x, 0, WIDTH*1.2), &(dest->x));
196 SDLNet_Write32(pack_float(src->y, 0, HEIGHT*1.2), &(dest->y));
197 SDLNet_Write32(pack_float(src->power, 0, 110), &(dest->power));
198 dest->use_power = src->use_power;
199 dest->score = src->score;
200 dest->desire = src->desire;
201 dest->game = src->game;
202 memcpy(dest->sets, src->sets, sizeof(unsigned char)*(SETS_TO_WIN*2));
203 SDLNet_Write32(pack_float(src->accelerate, 0, 200), &(dest->accelerate));
206 void
207 net_unserialize_player(const NetworkPlayer* src, Player* dest)
209 assert(src != NULL && dest != NULL);
210 dest->x = unpack_float(SDLNet_Read32(&(src->x)), 0, WIDTH*1.2);
211 dest->y = unpack_float(SDLNet_Read32(&(src->y)), 0, HEIGHT*1.2);
212 dest->power = unpack_float(SDLNet_Read32(&(src->power)), 0, 110);
213 dest->use_power = src->use_power;
214 dest->score = src->score;
215 dest->desire = src->desire;
216 dest->game = src->game;
217 memcpy(dest->sets, src->sets, sizeof(unsigned char)*(SETS_TO_WIN*2));
218 dest->accelerate = unpack_float(SDLNet_Read32(&(src->accelerate)), 0, 200);
221 void
222 net_serialize_gamestate(const GameState* src, NetworkGameState* dest)
224 int p;
226 assert(src != NULL && dest != NULL);
228 net_serialize_ball(&(src->ball), &(dest->ball));
229 for (p=0; p<MAXPLAYERS; p++) {
230 net_serialize_player(&(src->players[p]), &(dest->players[p]));
232 dest->serving_player = src->serving_player;
233 dest->referee = src->referee;
234 dest->current_set = src->current_set;
235 dest->winner = src->winner;
236 dest->sound_events = src->sound_events;
237 dest->score_event = src->score_event;
238 dest->ec_game = src->ec_game;
239 dest->ec_sets = src->ec_sets;
240 dest->status_message = src->status_message;
243 void
244 net_unserialize_gamestate(const NetworkGameState* src, GameState* dest)
246 int p;
248 assert(src != NULL && dest != NULL);
250 net_unserialize_ball(&(src->ball), &(dest->ball));
251 for (p=0; p<MAXPLAYERS; p++) {
252 net_unserialize_player(&(src->players[p]), &(dest->players[p]));
254 dest->serving_player = src->serving_player;
255 dest->referee = src->referee;
256 dest->current_set = src->current_set;
257 dest->winner = src->winner;
258 dest->sound_events = src->sound_events;
259 dest->score_event = src->score_event;
260 dest->ec_game = src->ec_game;
261 dest->ec_sets = src->ec_sets;
262 dest->status_message = src->status_message;