5 * Copyright (C) 2003, 2007, 2008, 2009 Thomas Perl <thp@thpinfo.com>
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,
32 #include <SDL/SDL_net.h>
34 /* HELPER FUNCTIONS */
37 pack_float(float v
, float min
, float max
)
39 assert(v
>= min
&& v
< max
);
40 return (Uint32
)((1U<<31) * (v
-min
) / (max
-min
));
44 unpack_float(Uint32 v
, float min
, float max
)
47 return v
* (max
-min
) / (1U<<31) + min
;
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
;
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
);
104 network_send_input(TennixNet
* connection
, NetworkInputData
* src
)
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
));
121 network_send_state(TennixNet
* connection
, GameState
* src
)
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);
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;
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;
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;
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
;
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
;
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
));
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);
235 net_serialize_gamestate(const GameState
* src
, NetworkGameState
* dest
)
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
;
257 net_unserialize_gamestate(NetworkGameState
* src
, GameState
* dest
)
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 */