Predictable ordering of tennix.tnx contents
[tennix.git] / src / network.cc
blob5538593eb138bbca878f98c628ad9d49431adba4
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 "config.h"
26 #ifdef HAVE_SDL_NET
28 #include "game.h"
29 #include "network.h"
31 #include <assert.h>
32 #include <SDL/SDL_net.h>
34 /* HELPER FUNCTIONS */
36 Uint32
37 pack_float(float v, float min, float max)
39 assert(v >= min && v < max);
40 return (Uint32)((1U<<31) * (v-min) / (max-min));
43 float
44 unpack_float(Uint32 v, float min, float max)
46 assert(v < (1U<<31));
47 return v * (max-min) / (1U<<31) + min;
50 void
51 init_network()
53 SDLNet_Init();
56 void
57 uninit_network()
59 SDLNet_Quit();
62 TennixNet*
63 network_connect(const char* host, bool master)
65 TennixNet* connection = (TennixNet*)malloc(sizeof(TennixNet));
66 assert(connection != NULL);
68 assert(SDLNet_ResolveHost(&(connection->peer), (const char*)host, 0) == 0);
69 connection->base_port_local = (master)?(TENNIXNET_PORT_MASTER):(TENNIXNET_PORT_SLAVE);
70 connection->base_port_remote = (master)?(TENNIXNET_PORT_SLAVE):(TENNIXNET_PORT_MASTER);
71 connection->input_packet = SDLNet_AllocPacket(sizeof(NetworkInputData));
72 connection->state_packet = SDLNet_AllocPacket(sizeof(NetworkGameState));
73 connection->input_available = false;
74 connection->state_available = false;
75 connection->send_socket = SDLNet_UDP_Open(0);
76 connection->recv_input_socket = SDLNet_UDP_Open(connection->base_port_local);
77 connection->recv_state_socket = SDLNet_UDP_Open(connection->base_port_local+1);
79 /* Fill with invalid data for first-time update */
80 connection->input_data.x = 0xFF;
81 connection->input_data.y = 0xFF;
82 connection->input_data.keys = 0xFF;
84 connection->master = master;
86 return connection;
89 void
90 network_disconnect(TennixNet* connection)
92 if (connection != NULL)
94 SDLNet_UDP_Close(connection->send_socket);
95 SDLNet_UDP_Close(connection->recv_input_socket);
96 SDLNet_UDP_Close(connection->recv_state_socket);
97 SDLNet_FreePacket(connection->input_packet);
98 SDLNet_FreePacket(connection->state_packet);
99 free(connection);
103 void
104 network_send_input(TennixNet* connection, NetworkInputData* src)
106 assert(src != NULL);
107 if (connection != NULL && memcmp(&(connection->input_data),
108 src, sizeof(NetworkInputData)) != 0) {
109 memcpy(connection->input_packet->data, src, sizeof(NetworkInputData));
110 connection->input_packet->address.host = connection->peer.host;
111 SDLNet_Write16(connection->base_port_remote, &(connection->input_packet->address.port));
112 connection->input_packet->channel = -1;
113 connection->input_packet->len = sizeof(NetworkInputData);
114 SDLNet_UDP_Send(connection->send_socket, -1, connection->input_packet);
115 /* Remember what we sent (what the remote end "sees") right now */
116 memcpy(&(connection->input_data), src, sizeof(NetworkInputData));
120 void
121 network_send_state(TennixNet* connection, GameState* src)
123 assert(src != NULL);
124 if (connection != NULL && connection->master) {
125 net_serialize_gamestate(src, (NetworkGameState*)(connection->state_packet->data));
126 connection->state_packet->address.host = connection->peer.host;
127 SDLNet_Write16(connection->base_port_remote+1, &(connection->state_packet->address.port));
128 connection->state_packet->channel = -1;
129 connection->state_packet->len = sizeof(NetworkGameState);
130 assert(SDLNet_UDP_Send(connection->send_socket, -1, connection->state_packet)!=0);
134 void
135 network_receive(TennixNet* connection)
137 if (connection != NULL) {
138 connection->input_packet->len = sizeof(NetworkInputData);
139 while (SDLNet_UDP_Recv(connection->recv_input_socket, connection->input_packet)) {
140 connection->input_available = true;
143 if (!(connection->master)) {
144 connection->state_packet->len = sizeof(NetworkGameState);
145 while (SDLNet_UDP_Recv(connection->recv_state_socket, connection->state_packet)) {
146 connection->state_available = true;
152 void
153 network_get_input(TennixNet* connection, NetworkInputData* dest)
155 assert(dest != NULL);
156 if (connection != NULL && connection->input_available) {
157 memcpy(dest, connection->input_packet->data, sizeof(NetworkInputData));
158 connection->input_available = false;
162 void
163 network_get_gamestate(TennixNet* connection, GameState* dest)
165 assert(dest != NULL);
166 if (connection != NULL && connection->state_available) {
167 net_unserialize_gamestate((NetworkGameState*)
168 (connection->state_packet->data), dest);
169 connection->state_available = false;
174 void
175 net_serialize_ball(const Ball* src, NetworkBall* dest)
177 assert(src != NULL && dest != NULL);
178 SDLNet_Write32(pack_float(src->x, -WIDTH, WIDTH*2), &(dest->x));
179 SDLNet_Write32(pack_float(src->y, -HEIGHT, HEIGHT*2), &(dest->y));
180 SDLNet_Write32(pack_float(src->z, -50, 50), &(dest->z));
181 SDLNet_Write32(pack_float(src->move_x, -50, 50), &(dest->move_x));
182 SDLNet_Write32(pack_float(src->move_y, -50, 50), &(dest->move_y));
183 SDLNet_Write32(pack_float(src->move_z, -50, 50), &(dest->move_z));
184 dest->ground_hit = src->ground_hit;
185 dest->last_hit_by = src->last_hit_by;
186 dest->inhibit_gravity = src->inhibit_gravity;
189 void
190 net_unserialize_ball(NetworkBall* src, Ball* dest)
192 assert(src != NULL && dest != NULL);
193 dest->x = unpack_float(SDLNet_Read32(&(src->x)), -WIDTH, WIDTH*2);
194 dest->y = unpack_float(SDLNet_Read32(&(src->y)), -HEIGHT, HEIGHT*2);
195 dest->z = unpack_float(SDLNet_Read32(&(src->z)), -50, 50);
196 dest->move_x = unpack_float(SDLNet_Read32(&(src->move_x)), -50, 50);
197 dest->move_y = unpack_float(SDLNet_Read32(&(src->move_y)), -50, 50);
198 dest->move_z = unpack_float(SDLNet_Read32(&(src->move_z)), -50, 50);
199 dest->ground_hit = src->ground_hit;
200 dest->last_hit_by = src->last_hit_by;
201 dest->inhibit_gravity = src->inhibit_gravity;
204 void
205 net_serialize_player(const Player* src, NetworkPlayer* dest)
207 assert(src != NULL && dest != NULL);
208 SDLNet_Write32(pack_float(src->x, 0, WIDTH*1.2), &(dest->x));
209 SDLNet_Write32(pack_float(src->y, 0, HEIGHT*1.2), &(dest->y));
210 SDLNet_Write32(pack_float(src->power, 0, 110), &(dest->power));
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 SDLNet_Write32(pack_float(src->accelerate, 0, 200), &(dest->accelerate));
219 void
220 net_unserialize_player(NetworkPlayer* src, Player* dest)
222 assert(src != NULL && dest != NULL);
223 dest->x = unpack_float(SDLNet_Read32(&(src->x)), 0, WIDTH*1.2);
224 dest->y = unpack_float(SDLNet_Read32(&(src->y)), 0, HEIGHT*1.2);
225 dest->power = unpack_float(SDLNet_Read32(&(src->power)), 0, 110);
226 dest->use_power = src->use_power;
227 dest->score = src->score;
228 dest->desire = (PlayerDesire)src->desire;
229 dest->game = src->game;
230 memcpy(dest->sets, src->sets, sizeof(unsigned char)*(SETS_TO_WIN*2));
231 dest->accelerate = unpack_float(SDLNet_Read32(&(src->accelerate)), 0, 200);
234 void
235 net_serialize_gamestate(const GameState* src, NetworkGameState* dest)
237 int p;
239 assert(src != NULL && dest != NULL);
241 net_serialize_ball(&(src->ball), &(dest->ball));
242 for (p=0; p<MAXPLAYERS; p++) {
243 net_serialize_player(&(src->players[p]), &(dest->players[p]));
245 dest->serving_player = src->serving_player;
246 dest->referee = src->referee;
247 dest->current_set = src->current_set;
248 dest->winner = src->winner;
249 dest->sound_events = src->sound_events;
250 dest->score_event = src->score_event;
251 dest->ec_game = src->ec_game;
252 dest->ec_sets = src->ec_sets;
253 dest->status_message = src->status_message;
256 void
257 net_unserialize_gamestate(NetworkGameState* src, GameState* dest)
259 int p;
261 assert(src != NULL && dest != NULL);
263 net_unserialize_ball(&(src->ball), &(dest->ball));
264 for (p=0; p<MAXPLAYERS; p++) {
265 net_unserialize_player(&(src->players[p]), &(dest->players[p]));
267 dest->serving_player = src->serving_player;
268 dest->referee = src->referee;
269 dest->current_set = src->current_set;
270 dest->winner = src->winner;
271 dest->sound_events = src->sound_events;
272 dest->score_event = src->score_event;
273 dest->ec_game = src->ec_game;
274 dest->ec_sets = src->ec_sets;
275 dest->status_message = src->status_message;
278 #endif /* HAVE_SDL_NET */