~ubuntu-branches/debian/stretch/opentyrian/stretch

« back to all changes in this revision

Viewing changes to src/network.c

  • Committer: Package Import Robot
  • Author(s): Etienne Millon
  • Date: 2015-03-31 08:48:54 UTC
  • Revision ID: package-import@ubuntu.com-20150331084854-f5a4uoz7uv3vopk6
Tags: upstream-2.1.20130907+dfsg
ImportĀ upstreamĀ versionĀ 2.1.20130907+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * OpenTyrian: A modern cross-platform port of Tyrian
 
3
 * Copyright (C) 2007-2009  The OpenTyrian Development Team
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public License
 
7
 * as published by the Free Software Foundation; either version 2
 
8
 * of the License, or (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
18
 */
 
19
#include "episodes.h"
 
20
#include "fonthand.h"
 
21
#include "helptext.h"
 
22
#include "joystick.h"
 
23
#include "keyboard.h"
 
24
#include "mainint.h"
 
25
#include "network.h"
 
26
#include "nortvars.h"
 
27
#include "opentyr.h"
 
28
#include "picload.h"
 
29
#include "sprite.h"
 
30
#include "varz.h"
 
31
#include "video.h"
 
32
 
 
33
#include <assert.h>
 
34
 
 
35
/*                              HERE BE DRAGONS!
 
36
 *
 
37
 * When I wrote this code I thought it was wonderful... that thought was very
 
38
 * wrong.  It works, but good luck understanding how... I don't anymore.
 
39
 *
 
40
 * Hopefully it'll be rewritten some day.
 
41
 */
 
42
 
 
43
#define NET_VERSION       2            // increment whenever networking changes might create incompatability
 
44
#define NET_PORT          1333         // UDP
 
45
 
 
46
#define NET_PACKET_SIZE   256
 
47
#define NET_PACKET_QUEUE  16
 
48
 
 
49
#define NET_RETRY         640          // ticks to wait for packet acknowledgement before resending
 
50
#define NET_RESEND        320          // ticks to wait before requesting unreceived game packet
 
51
#define NET_KEEP_ALIVE    1600         // ticks to wait between keep-alive packets
 
52
#define NET_TIME_OUT      16000        // ticks to wait before considering connection dead
 
53
 
 
54
bool isNetworkGame = false;
 
55
int network_delay = 1 + 1;  // minimum is 1 + 0
 
56
 
 
57
char *network_opponent_host = NULL;
 
58
 
 
59
Uint16 network_player_port = NET_PORT,
 
60
       network_opponent_port = NET_PORT;
 
61
 
 
62
static char empty_string[] = "";
 
63
char *network_player_name = empty_string,
 
64
     *network_opponent_name = empty_string;
 
65
 
 
66
#ifdef WITH_NETWORK
 
67
static UDPsocket socket;
 
68
static IPaddress ip;
 
69
 
 
70
UDPpacket *packet_out_temp;
 
71
static UDPpacket *packet_temp;
 
72
 
 
73
UDPpacket *packet_in[NET_PACKET_QUEUE] = { NULL },
 
74
          *packet_out[NET_PACKET_QUEUE] = { NULL };
 
75
 
 
76
static Uint16 last_out_sync = 0, queue_in_sync = 0, queue_out_sync = 0, last_ack_sync = 0;
 
77
static Uint32 last_in_tick = 0, last_out_tick = 0;
 
78
 
 
79
UDPpacket *packet_state_in[NET_PACKET_QUEUE] = { NULL };
 
80
static UDPpacket *packet_state_in_xor[NET_PACKET_QUEUE] = { NULL };
 
81
UDPpacket *packet_state_out[NET_PACKET_QUEUE] = { NULL };
 
82
 
 
83
static Uint16 last_state_in_sync = 0, last_state_out_sync = 0;
 
84
static Uint32 last_state_in_tick = 0;
 
85
 
 
86
static bool net_initialized = false;
 
87
static bool connected = false, quit = false;
 
88
#endif
 
89
 
 
90
uint thisPlayerNum = 0;  /* Player number on this PC (1 or 2) */
 
91
 
 
92
JE_boolean haltGame = false;
 
93
 
 
94
JE_boolean moveOk;
 
95
 
 
96
/* Special Requests */
 
97
JE_boolean pauseRequest, skipLevelRequest, helpRequest, nortShipRequest;
 
98
JE_boolean yourInGameMenuRequest, inGameMenuRequest;
 
99
 
 
100
#ifdef WITH_NETWORK
 
101
static void packet_copy( UDPpacket *dst, UDPpacket *src )
 
102
{
 
103
        void *temp = dst->data;
 
104
        memcpy(dst, src, sizeof(*dst));
 
105
        dst->data = temp;
 
106
        memcpy(dst->data, src->data, src->len);
 
107
}
 
108
 
 
109
static void packets_shift_up( UDPpacket **packet, int max_packets )
 
110
{
 
111
                if (packet[0])
 
112
                {
 
113
                        SDLNet_FreePacket(packet[0]);
 
114
                }
 
115
                for (int i = 0; i < max_packets - 1; i++)
 
116
                {
 
117
                        packet[i] = packet[i + 1];
 
118
                }
 
119
                packet[max_packets - 1] = NULL;
 
120
}
 
121
 
 
122
static void packets_shift_down( UDPpacket **packet, int max_packets )
 
123
{
 
124
        if (packet[max_packets - 1])
 
125
        {
 
126
                SDLNet_FreePacket(packet[max_packets - 1]);
 
127
        }
 
128
        for (int i = max_packets - 1; i > 0; i--)
 
129
        {
 
130
                packet[i] = packet[i - 1];
 
131
        }
 
132
        packet[0] = NULL;
 
133
}
 
134
 
 
135
// prepare new packet for sending
 
136
void network_prepare( Uint16 type )
 
137
{
 
138
        SDLNet_Write16(type,          &packet_out_temp->data[0]);
 
139
        SDLNet_Write16(last_out_sync, &packet_out_temp->data[2]);
 
140
}
 
141
 
 
142
// send packet but don't expect acknoledgment of delivery
 
143
static bool network_send_no_ack( int len )
 
144
{
 
145
        packet_out_temp->len = len;
 
146
 
 
147
        if (!SDLNet_UDP_Send(socket, 0, packet_out_temp))
 
148
        {
 
149
                printf("SDLNet_UDP_Send: %s\n", SDL_GetError());
 
150
                return false;
 
151
        }
 
152
 
 
153
        return true;
 
154
}
 
155
 
 
156
// send packet and place it in queue to be acknowledged
 
157
bool network_send( int len )
 
158
{
 
159
        bool temp = network_send_no_ack(len);
 
160
 
 
161
        Uint16 i = last_out_sync - queue_out_sync;
 
162
        if (i < NET_PACKET_QUEUE)
 
163
        {
 
164
                packet_out[i] = SDLNet_AllocPacket(NET_PACKET_SIZE);
 
165
                packet_copy(packet_out[i], packet_out_temp);
 
166
        } else {
 
167
                // connection is probably bad now
 
168
                fprintf(stderr, "warning: outbound packet queue overflow\n");
 
169
                return false;
 
170
        }
 
171
 
 
172
        last_out_sync++;
 
173
 
 
174
        if (network_is_sync())
 
175
                last_out_tick = SDL_GetTicks();
 
176
 
 
177
        return temp;
 
178
}
 
179
 
 
180
// send acknowledgement packet
 
181
static int network_acknowledge( Uint16 sync )
 
182
{
 
183
        SDLNet_Write16(PACKET_ACKNOWLEDGE, &packet_out_temp->data[0]);
 
184
        SDLNet_Write16(sync,               &packet_out_temp->data[2]);
 
185
        network_send_no_ack(4);
 
186
 
 
187
        return 0;
 
188
}
 
189
 
 
190
// activity lately?
 
191
static bool network_is_alive( void )
 
192
{
 
193
        return (SDL_GetTicks() - last_in_tick < NET_TIME_OUT || SDL_GetTicks() - last_state_in_tick < NET_TIME_OUT);
 
194
}
 
195
 
 
196
// poll for new packets received, check that connection is alive, resend queued packets if necessary
 
197
int network_check( void )
 
198
{
 
199
        if (!net_initialized)
 
200
                return -1;
 
201
 
 
202
        if (connected)
 
203
        {
 
204
                // timeout
 
205
                if (!network_is_alive())
 
206
                {
 
207
                        if (!quit)
 
208
                                network_tyrian_halt(2, false);
 
209
                }
 
210
 
 
211
                // keep-alive
 
212
                static Uint32 keep_alive_tick = 0;
 
213
                if (SDL_GetTicks() - keep_alive_tick > NET_KEEP_ALIVE)
 
214
                {
 
215
                        network_prepare(PACKET_KEEP_ALIVE);
 
216
                        network_send_no_ack(4);
 
217
 
 
218
                        keep_alive_tick = SDL_GetTicks();
 
219
                }
 
220
        }
 
221
 
 
222
        // retry
 
223
        if (packet_out[0] && SDL_GetTicks() - last_out_tick > NET_RETRY)
 
224
        {
 
225
                if (!SDLNet_UDP_Send(socket, 0, packet_out[0]))
 
226
                {
 
227
                        printf("SDLNet_UDP_Send: %s\n", SDL_GetError());
 
228
                        return -1;
 
229
                }
 
230
 
 
231
                last_out_tick = SDL_GetTicks();
 
232
        }
 
233
 
 
234
        switch (SDLNet_UDP_Recv(socket, packet_temp))
 
235
        {
 
236
                case -1:
 
237
                        printf("SDLNet_UDP_Recv: %s\n", SDL_GetError());
 
238
                        return -1;
 
239
                        break;
 
240
                case 0:
 
241
                        break;
 
242
                default:
 
243
                        if (packet_temp->channel == 0 && packet_temp->len >= 4)
 
244
                        {
 
245
                                switch (SDLNet_Read16(&packet_temp->data[0]))
 
246
                                {
 
247
                                        case PACKET_ACKNOWLEDGE:
 
248
                                                if ((Uint16)(SDLNet_Read16(&packet_temp->data[2]) - last_ack_sync) < NET_PACKET_QUEUE)
 
249
                                                {
 
250
                                                        last_ack_sync = SDLNet_Read16(&packet_temp->data[2]);
 
251
                                                }
 
252
 
 
253
                                                {
 
254
                                                        Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - queue_out_sync;
 
255
                                                        if (i < NET_PACKET_QUEUE)
 
256
                                                        {
 
257
                                                                if (packet_out[i])
 
258
                                                                {
 
259
                                                                        SDLNet_FreePacket(packet_out[i]);
 
260
                                                                        packet_out[i] = NULL;
 
261
                                                                }
 
262
                                                        }
 
263
                                                }
 
264
 
 
265
                                                // remove acknowledged packets from queue
 
266
                                                while (packet_out[0] == NULL && (Uint16)(last_ack_sync - queue_out_sync) < NET_PACKET_QUEUE)
 
267
                                                {
 
268
                                                        packets_shift_up(packet_out, NET_PACKET_QUEUE);
 
269
 
 
270
                                                        queue_out_sync++;
 
271
                                                }
 
272
 
 
273
                                                last_in_tick = SDL_GetTicks();
 
274
                                                break;
 
275
 
 
276
                                        case PACKET_CONNECT:
 
277
                                                queue_in_sync = SDLNet_Read16(&packet_temp->data[2]);
 
278
 
 
279
                                                for (int i = 0; i < NET_PACKET_QUEUE; i++)
 
280
                                                {
 
281
                                                        if (packet_in[i])
 
282
                                                        {
 
283
                                                                SDLNet_FreePacket(packet_in[i]);
 
284
                                                                packet_in[i] = NULL;
 
285
                                                        }
 
286
                                                }
 
287
 
 
288
                                        case PACKET_DETAILS:
 
289
                                        case PACKET_WAITING:
 
290
                                        case PACKET_BUSY:
 
291
                                        case PACKET_GAME_QUIT:
 
292
                                        case PACKET_GAME_PAUSE:
 
293
                                        case PACKET_GAME_MENU:
 
294
                                                {
 
295
                                                        Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - queue_in_sync;
 
296
                                                        if (i < NET_PACKET_QUEUE)
 
297
                                                        {
 
298
                                                                if (packet_in[i] == NULL)
 
299
                                                                        packet_in[i] = SDLNet_AllocPacket(NET_PACKET_SIZE);
 
300
                                                                packet_copy(packet_in[i], packet_temp);
 
301
                                                        } else {
 
302
                                                                // inbound packet queue overflow/underflow
 
303
                                                                // under normal circumstances, this is okay
 
304
                                                        }
 
305
                                                }
 
306
 
 
307
                                                network_acknowledge(SDLNet_Read16(&packet_temp->data[2]));
 
308
 
 
309
                                        case PACKET_KEEP_ALIVE:
 
310
                                                last_in_tick = SDL_GetTicks();
 
311
                                                break;
 
312
 
 
313
                                        case PACKET_QUIT:
 
314
                                                if (!quit)
 
315
                                                {
 
316
                                                        network_prepare(PACKET_QUIT);
 
317
                                                        network_send(4);  // PACKET_QUIT
 
318
                                                }
 
319
 
 
320
                                                network_acknowledge(SDLNet_Read16(&packet_temp->data[2]));
 
321
 
 
322
                                                if (!quit)
 
323
                                                        network_tyrian_halt(1, true);
 
324
                                                break;
 
325
 
 
326
                                        case PACKET_STATE:
 
327
                                                // place packet in queue if within limits
 
328
                                                {
 
329
                                                        Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - last_state_in_sync + 1;
 
330
                                                        if (i < NET_PACKET_QUEUE)
 
331
                                                        {
 
332
                                                                if (packet_state_in[i] == NULL)
 
333
                                                                        packet_state_in[i] = SDLNet_AllocPacket(NET_PACKET_SIZE);
 
334
                                                                packet_copy(packet_state_in[i], packet_temp);
 
335
                                                        }
 
336
                                                }
 
337
                                                break;
 
338
 
 
339
                                        case PACKET_STATE_XOR:
 
340
                                                // place packet in queue if within limits
 
341
                                                {
 
342
                                                        Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - last_state_in_sync + 1;
 
343
                                                        if (i < NET_PACKET_QUEUE)
 
344
                                                        {
 
345
                                                                if (packet_state_in_xor[i] == NULL)
 
346
                                                                {
 
347
                                                                        packet_state_in_xor[i] = SDLNet_AllocPacket(NET_PACKET_SIZE);
 
348
                                                                        packet_copy(packet_state_in_xor[i], packet_temp);
 
349
                                                                } else if (SDLNet_Read16(&packet_state_in_xor[i]->data[0]) != PACKET_STATE_XOR) {
 
350
                                                                        for (int j = 4; j < packet_state_in_xor[i]->len; j++)
 
351
                                                                                packet_state_in_xor[i]->data[j] ^= packet_temp->data[j];
 
352
                                                                        SDLNet_Write16(PACKET_STATE_XOR, &packet_state_in_xor[i]->data[0]);
 
353
                                                                }
 
354
                                                        }
 
355
                                                }
 
356
                                                break;
 
357
 
 
358
                                        case PACKET_STATE_RESEND:
 
359
                                                // resend requested state packet if still available
 
360
                                                {
 
361
                                                        Uint16 i = last_state_out_sync - SDLNet_Read16(&packet_temp->data[2]);
 
362
                                                        if (i > 0 && i < NET_PACKET_QUEUE)
 
363
                                                        {
 
364
                                                                if (packet_state_out[i])
 
365
                                                                {
 
366
                                                                        if (!SDLNet_UDP_Send(socket, 0, packet_state_out[i]))
 
367
                                                                        {
 
368
                                                                                printf("SDLNet_UDP_Send: %s\n", SDL_GetError());
 
369
                                                                                return -1;
 
370
                                                                        }
 
371
                                                                }
 
372
                                                        }
 
373
                                                }
 
374
                                                break;
 
375
 
 
376
                                        default:
 
377
                                                fprintf(stderr, "warning: bad packet %d received\n", SDLNet_Read16(&packet_temp->data[0]));
 
378
                                                return 0;
 
379
                                                break;
 
380
                                }
 
381
 
 
382
                                return 1;
 
383
                        }
 
384
                        break;
 
385
        }
 
386
 
 
387
        return 0;
 
388
}
 
389
 
 
390
// discard working packet, now processing next packet in queue
 
391
bool network_update( void )
 
392
{
 
393
        if (packet_in[0])
 
394
        {
 
395
                packets_shift_up(packet_in, NET_PACKET_QUEUE);
 
396
 
 
397
                queue_in_sync++;
 
398
 
 
399
                return true;
 
400
        }
 
401
 
 
402
        return false;
 
403
}
 
404
 
 
405
// has opponent gotten all the packets we've sent?
 
406
bool network_is_sync( void )
 
407
{
 
408
        return (queue_out_sync - last_ack_sync == 1);
 
409
}
 
410
 
 
411
 
 
412
// prepare new state for sending
 
413
void network_state_prepare( void )
 
414
{
 
415
        if (packet_state_out[0])
 
416
        {
 
417
                fprintf(stderr, "warning: state packet overwritten (previous packet remains unsent)\n");
 
418
        } else {
 
419
                packet_state_out[0] = SDLNet_AllocPacket(NET_PACKET_SIZE);
 
420
                packet_state_out[0]->len = 28;
 
421
        }
 
422
 
 
423
        SDLNet_Write16(PACKET_STATE, &packet_state_out[0]->data[0]);
 
424
        SDLNet_Write16(last_state_out_sync, &packet_state_out[0]->data[2]);
 
425
        memset(&packet_state_out[0]->data[4], 0, 28 - 4);
 
426
}
 
427
 
 
428
// send state packet, xor packet if applicable
 
429
int network_state_send( void )
 
430
{
 
431
        if (!SDLNet_UDP_Send(socket, 0, packet_state_out[0]))
 
432
        {
 
433
                printf("SDLNet_UDP_Send: %s\n", SDL_GetError());
 
434
                return -1;
 
435
        }
 
436
 
 
437
        // send xor of last network_delay packets
 
438
        if (network_delay > 1 && (last_state_out_sync + 1) % network_delay == 0 && packet_state_out[network_delay - 1] != NULL)
 
439
        {
 
440
                packet_copy(packet_temp, packet_state_out[0]);
 
441
                SDLNet_Write16(PACKET_STATE_XOR, &packet_temp->data[0]);
 
442
                for (int i = 1; i < network_delay; i++)
 
443
                        for (int j = 4; j < packet_temp->len; j++)
 
444
                                packet_temp->data[j] ^= packet_state_out[i]->data[j];
 
445
 
 
446
                if (!SDLNet_UDP_Send(socket, 0, packet_temp))
 
447
                {
 
448
                        printf("SDLNet_UDP_Send: %s\n", SDL_GetError());
 
449
                        return -1;
 
450
                }
 
451
        }
 
452
 
 
453
        packets_shift_down(packet_state_out, NET_PACKET_QUEUE);
 
454
 
 
455
        last_state_out_sync++;
 
456
 
 
457
        return 0;
 
458
}
 
459
 
 
460
// receive state packet, wait until received
 
461
bool network_state_update( void )
 
462
{
 
463
        if (network_state_is_reset())
 
464
        {
 
465
                return 0;
 
466
        } else {
 
467
                packets_shift_up(packet_state_in, NET_PACKET_QUEUE);
 
468
 
 
469
                packets_shift_up(packet_state_in_xor, NET_PACKET_QUEUE);
 
470
 
 
471
                last_state_in_sync++;
 
472
 
 
473
                // current xor packet index
 
474
                int x = network_delay - (last_state_in_sync - 1) % network_delay - 1;
 
475
 
 
476
                // loop until needed packet is available
 
477
                while (!packet_state_in[0])
 
478
                {
 
479
                        // xor the packet from thin air, if possible
 
480
                        if (packet_state_in_xor[x] && SDLNet_Read16(&packet_state_in_xor[x]->data[0]) == PACKET_STATE_XOR)
 
481
                        {
 
482
                                // check for all other required packets
 
483
                                bool okay = true;
 
484
                                for (int i = 1; i <= x; i++)
 
485
                                {
 
486
                                        if (packet_state_in[i] == NULL)
 
487
                                        {
 
488
                                                okay = false;
 
489
                                                break;
 
490
                                        }
 
491
                                }
 
492
                                if (okay)
 
493
                                {
 
494
                                        packet_state_in[0] = SDLNet_AllocPacket(NET_PACKET_SIZE);
 
495
                                        packet_copy(packet_state_in[0], packet_state_in_xor[x]);
 
496
                                        for (int i = 1; i <= x; i++)
 
497
                                                for (int j = 4; j < packet_state_in[0]->len; j++)
 
498
                                                        packet_state_in[0]->data[j] ^= packet_state_in[i]->data[j];
 
499
                                        break;
 
500
                                }
 
501
                        }
 
502
 
 
503
                        static Uint32 resend_tick = 0;
 
504
                        if (SDL_GetTicks() - last_state_in_tick > NET_RESEND && SDL_GetTicks() - resend_tick > NET_RESEND)
 
505
                        {
 
506
                                SDLNet_Write16(PACKET_STATE_RESEND,    &packet_out_temp->data[0]);
 
507
                                SDLNet_Write16(last_state_in_sync - 1, &packet_out_temp->data[2]);
 
508
                                network_send_no_ack(4);  // PACKET_RESEND
 
509
 
 
510
                                resend_tick = SDL_GetTicks();
 
511
                        }
 
512
 
 
513
                        if (network_check() == 0)
 
514
                                SDL_Delay(1);
 
515
                }
 
516
 
 
517
                if (network_delay > 1)
 
518
                {
 
519
                        // process the current in packet against the xor queue
 
520
                        if (packet_state_in_xor[x] == NULL)
 
521
                        {
 
522
                                packet_state_in_xor[x] = SDLNet_AllocPacket(NET_PACKET_SIZE);
 
523
                                packet_copy(packet_state_in_xor[x], packet_state_in[0]);
 
524
                                packet_state_in_xor[x]->status = 0;
 
525
                        } else {
 
526
                                for (int j = 4; j < packet_state_in_xor[x]->len; j++)
 
527
                                        packet_state_in_xor[x]->data[j] ^= packet_state_in[0]->data[j];
 
528
                        }
 
529
                }
 
530
 
 
531
                last_state_in_tick = SDL_GetTicks();
 
532
        }
 
533
 
 
534
        return 1;
 
535
}
 
536
 
 
537
// ignore first network_delay states of level
 
538
bool network_state_is_reset( void )
 
539
{
 
540
        return (last_state_out_sync < network_delay);
 
541
}
 
542
 
 
543
// reset queues for new level
 
544
void network_state_reset( void )
 
545
{
 
546
        last_state_in_sync = last_state_out_sync = 0;
 
547
 
 
548
        for (int i = 0; i < NET_PACKET_QUEUE; i++)
 
549
        {
 
550
                if (packet_state_in[i])
 
551
                {
 
552
                        SDLNet_FreePacket(packet_state_in[i]);
 
553
                        packet_state_in[i] = NULL;
 
554
                }
 
555
        }
 
556
        for (int i = 0; i < NET_PACKET_QUEUE; i++)
 
557
        {
 
558
                if (packet_state_in_xor[i])
 
559
                {
 
560
                        SDLNet_FreePacket(packet_state_in_xor[i]);
 
561
                        packet_state_in_xor[i] = NULL;
 
562
                }
 
563
        }
 
564
        for (int i = 0; i < NET_PACKET_QUEUE; i++)
 
565
        {
 
566
                if (packet_state_out[i])
 
567
                {
 
568
                        SDLNet_FreePacket(packet_state_out[i]);
 
569
                        packet_state_out[i] = NULL;
 
570
                }
 
571
        }
 
572
 
 
573
        last_state_in_tick = SDL_GetTicks();
 
574
}
 
575
 
 
576
 
 
577
// attempt to punch through firewall by firing off UDP packets at the opponent
 
578
// exchange game information
 
579
int network_connect( void )
 
580
{
 
581
        SDLNet_ResolveHost(&ip, network_opponent_host, network_opponent_port);
 
582
 
 
583
        SDLNet_UDP_Bind(socket, 0, &ip);
 
584
 
 
585
        Uint16 episodes = 0, episodes_local = 0;
 
586
        assert(EPISODE_MAX <= 16);
 
587
        for (int i = EPISODE_MAX - 1; i >= 0; i--)
 
588
        {
 
589
                episodes <<= 1;
 
590
                episodes |= (episodeAvail[i] != 0);
 
591
        }
 
592
        episodes_local = episodes;
 
593
 
 
594
        assert(NET_PACKET_SIZE - 12 >= 20 + 1);
 
595
        if (strlen(network_player_name) > 20)
 
596
                network_player_name[20] = '\0';
 
597
 
 
598
connect_reset:
 
599
        network_prepare(PACKET_CONNECT);
 
600
        SDLNet_Write16(NET_VERSION, &packet_out_temp->data[4]);
 
601
        SDLNet_Write16(network_delay,   &packet_out_temp->data[6]);
 
602
        SDLNet_Write16(episodes_local,  &packet_out_temp->data[8]);
 
603
        SDLNet_Write16(thisPlayerNum,   &packet_out_temp->data[10]);
 
604
        strcpy((char *)&packet_out_temp->data[12], network_player_name);
 
605
        network_send(12 + strlen(network_player_name) + 1); // PACKET_CONNECT
 
606
 
 
607
        // until opponent sends connect packet
 
608
        while (true)
 
609
        {
 
610
                push_joysticks_as_keyboard();
 
611
                service_SDL_events(false);
 
612
 
 
613
                if (newkey && lastkey_sym == SDLK_ESCAPE)
 
614
                        network_tyrian_halt(0, false);
 
615
 
 
616
                // never timeout
 
617
                last_in_tick = SDL_GetTicks();
 
618
 
 
619
                if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_CONNECT)
 
620
                        break;
 
621
 
 
622
                network_update();
 
623
                network_check();
 
624
 
 
625
                SDL_Delay(16);
 
626
        }
 
627
 
 
628
connect_again:
 
629
        if (SDLNet_Read16(&packet_in[0]->data[4]) != NET_VERSION)
 
630
        {
 
631
                fprintf(stderr, "error: network version did not match opponent's\n");
 
632
                network_tyrian_halt(4, true);
 
633
        }
 
634
        if (SDLNet_Read16(&packet_in[0]->data[6]) != network_delay)
 
635
        {
 
636
                fprintf(stderr, "error: network delay did not match opponent's\n");
 
637
                network_tyrian_halt(5, true);
 
638
        }
 
639
        if (SDLNet_Read16(&packet_in[0]->data[10]) == thisPlayerNum)
 
640
        {
 
641
                fprintf(stderr, "error: player number conflicts with opponent's\n");
 
642
                network_tyrian_halt(6, true);
 
643
        }
 
644
 
 
645
        episodes = SDLNet_Read16(&packet_in[0]->data[8]);
 
646
        for (int i = 0; i < EPISODE_MAX; i++) {
 
647
                episodeAvail[i] &= (episodes & 1);
 
648
                episodes >>= 1;
 
649
        }
 
650
 
 
651
        network_opponent_name = malloc(packet_in[0]->len - 12 + 1);
 
652
        strcpy(network_opponent_name, (char *)&packet_in[0]->data[12]);
 
653
 
 
654
        network_update();
 
655
 
 
656
        // until opponent has acknowledged
 
657
        while (!network_is_sync())
 
658
        {
 
659
                service_SDL_events(false);
 
660
 
 
661
                // got a duplicate packet; process it again (but why?)
 
662
                if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_CONNECT)
 
663
                        goto connect_again;
 
664
 
 
665
                network_check();
 
666
 
 
667
                // maybe opponent didn't get our packet
 
668
                if (SDL_GetTicks() - last_out_tick > NET_RETRY)
 
669
                        goto connect_reset;
 
670
 
 
671
                SDL_Delay(16);
 
672
        }
 
673
 
 
674
        // send another packet since sometimes the network syncs without both connect packets exchanged
 
675
        // there should be a better way to handle this
 
676
        network_prepare(PACKET_CONNECT);
 
677
        SDLNet_Write16(NET_VERSION, &packet_out_temp->data[4]);
 
678
        SDLNet_Write16(network_delay,   &packet_out_temp->data[6]);
 
679
        SDLNet_Write16(episodes_local,  &packet_out_temp->data[8]);
 
680
        SDLNet_Write16(thisPlayerNum,   &packet_out_temp->data[10]);
 
681
        strcpy((char *)&packet_out_temp->data[12], network_player_name);
 
682
        network_send(12 + strlen(network_player_name) + 1); // PACKET_CONNECT
 
683
 
 
684
        connected = true;
 
685
 
 
686
        return 0;
 
687
}
 
688
 
 
689
// something has gone wrong :(
 
690
void network_tyrian_halt( unsigned int err, bool attempt_sync )
 
691
{
 
692
        const char *err_msg[] = {
 
693
                "Quitting...",
 
694
                "Other player quit the game.",
 
695
                "Network connection was lost.",
 
696
                "Network connection failed.",
 
697
                "Network version mismatch.",
 
698
                "Network delay mismatch.",
 
699
                "Network player number conflict.",
 
700
        };
 
701
 
 
702
        quit = true;
 
703
 
 
704
        if (err >= COUNTOF(err_msg))
 
705
                err = 0;
 
706
 
 
707
        fade_black(10);
 
708
 
 
709
        VGAScreen = VGAScreenSeg;
 
710
 
 
711
        JE_loadPic(VGAScreen, 2, false);
 
712
        JE_dString(VGAScreen, JE_fontCenter(err_msg[err], SMALL_FONT_SHAPES), 140, err_msg[err], SMALL_FONT_SHAPES);
 
713
 
 
714
        JE_showVGA();
 
715
        fade_palette(colors, 10, 0, 255);
 
716
 
 
717
        if (attempt_sync)
 
718
        {
 
719
                while (!network_is_sync() && network_is_alive())
 
720
                {
 
721
                        service_SDL_events(false);
 
722
 
 
723
                        network_check();
 
724
                        SDL_Delay(16);
 
725
                }
 
726
        }
 
727
 
 
728
        if (err)
 
729
        {
 
730
                while (!JE_anyButton())
 
731
                        SDL_Delay(16);
 
732
        }
 
733
 
 
734
        fade_black(10);
 
735
 
 
736
        SDLNet_Quit();
 
737
 
 
738
        JE_tyrianHalt(5);
 
739
}
 
740
 
 
741
int network_init( void )
 
742
{
 
743
        printf("Initializing network...\n");
 
744
 
 
745
        if (network_delay * 2 > NET_PACKET_QUEUE - 2)
 
746
        {
 
747
                fprintf(stderr, "error: network delay would overflow packet queue\n");
 
748
                return -4;
 
749
        }
 
750
 
 
751
        if (SDLNet_Init() == -1)
 
752
        {
 
753
                fprintf(stderr, "error: SDLNet_Init: %s\n", SDLNet_GetError());
 
754
                return -1;
 
755
        }
 
756
 
 
757
        socket = SDLNet_UDP_Open(network_player_port);
 
758
        if (!socket)
 
759
        {
 
760
                fprintf(stderr, "error: SDLNet_UDP_Open: %s\n", SDLNet_GetError());
 
761
                return -2;
 
762
        }
 
763
 
 
764
        packet_temp = SDLNet_AllocPacket(NET_PACKET_SIZE);
 
765
        packet_out_temp = SDLNet_AllocPacket(NET_PACKET_SIZE);
 
766
 
 
767
        if (!packet_temp || !packet_out_temp)
 
768
        {
 
769
                printf("SDLNet_AllocPacket: %s\n", SDLNet_GetError());
 
770
                return -3;
 
771
        }
 
772
 
 
773
        net_initialized = true;
 
774
 
 
775
        return 0;
 
776
}
 
777
 
 
778
#endif
 
779
 
 
780
void JE_clearSpecialRequests( void )
 
781
{
 
782
        pauseRequest = false;
 
783
        inGameMenuRequest = false;
 
784
        skipLevelRequest = false;
 
785
        helpRequest = false;
 
786
        nortShipRequest = false;
 
787
}
 
788