source: abuse/trunk/src/innet.cpp @ 494

Last change on this file since 494 was 494, checked in by Sam Hocevar, 11 years ago

style: remove trailing spaces, fix copyright statements.

File size: 18.6 KB
Line 
1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
4 *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
5 *
6 *  This software was released into the Public Domain. As with most public
7 *  domain software, no warranty is made or implied by Crack dot Com or
8 *  Jonathan Clark.
9 */
10
11#include "config.h"
12
13#include <stdio.h>
14
15#include "demo.h"
16#include "macs.h"
17#include "specs.h"
18#include "level.h"
19#include "game.h"
20#include "dev.h"
21#include "timing.h"
22#include "fileman.h"
23#include "netface.h"
24
25#include "gserver.h"
26#include "gclient.h"
27#include "dprint.h"
28#include "netcfg.h"
29
30/*
31
32  This file is a combination of :
33    src/net/unix/unixnfc.c
34    src/net/unix/netdrv.c
35    src/net/unix/undrv.c
36
37    netdrv & undrv compile to a stand-alone program with talk with unixnfc
38via a FIFO in /tmp, using a RPC-like scheme.  This versions runs inside
39of a abuse and therefore is a bit simpler.
40*/
41
42base_memory_struct *base;   // points to shm_addr
43base_memory_struct local_base;
44net_address *net_server=NULL;
45net_protocol *prot=NULL;
46net_socket *comm_sock=NULL,*game_sock=NULL;
47extern char lsf[256];
48game_handler *game_face=NULL;
49int local_client_number=0;        // 0 is the server
50join_struct *join_array=NULL;      // points to an array of possible joining clients
51extern char *get_login();
52extern void set_login(char const *name);
53
54
55int net_init(int argc, char **argv)
56{
57    int i,x,db_level=0;
58    base=&local_base;
59
60    local_client_number=0;
61
62    if (!main_net_cfg)
63        main_net_cfg=new net_configuration;
64
65    for (i=1; i<argc; i++)
66    {
67        if (!strcmp(argv[i],"-nonet"))
68        {
69            printf( "Net: Disabled (-nonet)\n" );
70            return 0;
71        }
72        else if (!strcmp(argv[i],"-port"))
73        {
74            if( i == argc - 1 ||
75                !sscanf( argv[i + 1], "%d", &x ) ||
76                x < 1 || x > 0x7fff )
77            {
78                fprintf( stderr, "Net: Bad value following -port, use 1..32000\n" );
79                return 0;
80            }
81            else
82            {
83                main_net_cfg->port = x;
84            }
85        }
86        else if( !strcmp( argv[i], "-net" ) && i < argc-1 )
87        {
88            i++;
89            strcpy( main_net_cfg->server_name, argv[i] );
90            main_net_cfg->state = net_configuration::CLIENT;
91        }
92        else if (!strcmp(argv[i],"-ndb"))
93        {
94            if (i==argc-1 || !sscanf(argv[i+1],"%d",&x) || x<1 || x>3)
95            {
96                fprintf(stderr,"Net: Bad value following -ndb, use 1..3\n" );
97                return 0;
98            }
99            else
100            {
101                db_level = x;
102            }
103        }
104        else if( !strcmp( argv[i], "-server" ) )
105        {
106            main_net_cfg->state = net_configuration::SERVER;
107        }
108        else if( !strcmp( argv[i], "-min_players" ) )
109        {
110            i++;
111            int x = atoi( argv[i] );
112            if (x >= 1 && x <= 8)
113            {
114                main_net_cfg->min_players=x;
115            }
116            else
117            {
118                fprintf(stderr,"bad value for min_players use 1..8\n");
119            }
120        }
121    }
122
123    net_protocol *n = net_protocol::first, *usable = NULL;     // find a usable protocol from installed list
124    int total_usable = 0;
125    for( ; n; n = n->next )                                    // show a list of usables, just to be cute
126    {
127        fprintf( stderr, "Protocol %s : ",n->installed() ? "Installed" : "Not_installed" );
128        fprintf( stderr, "%s\n", n->name() );
129        if( n->installed() )
130        {
131            total_usable++;
132            usable=n;
133        }
134    }
135
136    if (!usable)
137    {
138        fprintf(stderr,"Net: No network protocols installed\n");
139        return 0;
140    }
141    prot=usable;
142    prot->set_debug_printing((net_protocol::debug_type)db_level);
143    if (main_net_cfg->state==net_configuration::SERVER)
144        set_login(main_net_cfg->name);
145
146    comm_sock=game_sock=NULL;
147    if (main_net_cfg->state==net_configuration::CLIENT)
148    {
149        dprintf("Attempting to locate server %s, please wait\n",main_net_cfg->server_name);
150        char const *sn=main_net_cfg->server_name;
151        net_server=prot->get_node_address(sn,DEFAULT_COMM_PORT,0);
152        if (!net_server)
153        {
154            dprintf(symbol_str("unable_locate"));
155            exit(0);
156        }
157        dprintf("Server located!  Please wait while data loads....\n");
158    }
159
160    fman=new file_manager(argc,argv,prot);                                       // manages remote file access
161    game_face=new game_handler;
162    join_array=(join_struct *)malloc(sizeof(join_struct)*MAX_JOINERS);
163    base->join_list=NULL;
164    base->mem_lock=0;
165    base->calc_crcs=0;
166    base->get_lsf=0;
167    base->wait_reload=0;
168    base->need_reload=0;
169    base->input_state=INPUT_COLLECTING;
170    base->current_tick=0;
171    base->packet.packet_reset();
172
173    return 1;
174}
175
176
177
178
179int net_start()  // is the game starting up off the net? (i.e. -net hostname)
180{   return (main_net_cfg && main_net_cfg->state==net_configuration::CLIENT);  }
181
182
183
184int kill_net()
185{
186  if (game_face) delete game_face;  game_face=NULL;
187  if (join_array) free(join_array);  join_array=NULL;
188  if (game_sock) { delete game_sock; game_sock=NULL; }
189  if (comm_sock) { delete comm_sock; comm_sock=NULL; }
190  delete fman;  fman=NULL;
191  if (net_server) { delete net_server; net_server=NULL; }
192  if (prot)
193  {
194
195    prot->cleanup();
196    prot=NULL;
197    return 1;
198  } else return 0;
199}
200
201void net_uninit()
202{
203  kill_net();
204}
205
206
207int NF_set_file_server(net_address *addr)
208{
209  if (prot)
210  {
211    fman->set_default_fs(addr);
212    net_socket *sock=prot->connect_to_server(addr,net_socket::SOCKET_SECURE);
213
214    if (!sock) { printf("set_file_server::connect failed\n"); return 0; }
215    uint8_t cmd=CLIENT_CRC_WAITER;
216    if ( (sock->write(&cmd,1)!=1 && printf("set_file_server::writefailed\n")) ||
217     (sock->read(&cmd,1)!=1  && printf("set_file_server::read failed\n")))        // wait for confirmation that crc's are written
218    { delete sock; return 0; }
219    delete sock;
220    return cmd;
221  } else return 0;
222}
223
224int NF_set_file_server(char const *name)
225{
226  if (prot)
227  {
228    net_address *addr=prot->get_node_address(name,DEFAULT_COMM_PORT,0);
229    if (addr)
230    {
231      int ret=NF_set_file_server(addr);
232      delete addr;
233      return ret;
234    } else return 0;
235  } else return 0;
236}
237
238
239int NF_open_file(char const *filename, char const *mode)
240{
241  if (prot)
242    return fman->rf_open_file(filename,mode);
243  else return -2;
244}
245
246
247long NF_close(int fd)
248{
249  if (prot)
250    return fman->rf_close(fd);
251  else return 0;
252}
253
254long NF_read(int fd, void *buf, long size)
255{
256  if (prot)
257    return fman->rf_read(fd,buf,size);
258  else return 0;
259}
260
261long NF_filelength(int fd)
262{
263  if (prot)
264    return fman->rf_file_size(fd);
265  else return 0;
266}
267
268long NF_seek(int fd, long offset)
269{
270  if (prot)
271    return fman->rf_seek(fd,offset);
272  else return 0;
273}
274
275long NF_tell(int fd)
276{
277  if (prot)
278    return fman->rf_tell(fd);
279  else return 0;
280}
281
282
283void service_net_request()
284{
285  if (prot)
286  {
287    if (prot->select(0))  // anything happening net-wise?
288    {
289      if (comm_sock && comm_sock->ready_to_read())  // new connection?
290      {
291                net_address *addr;
292
293                net_socket *new_sock=comm_sock->accept(addr);
294                if (new_sock)
295                {
296                  uint8_t client_type;
297                  if (new_sock->read(&client_type,1)!=1)
298                  {
299                    delete addr;
300                    delete new_sock;
301                  }
302                  else
303                  {
304                    switch (client_type)
305                    {
306                      case CLIENT_NFS :
307                      {
308                                delete addr;
309                                fman->add_nfs_client(new_sock);
310                      } break;
311                      case CLIENT_CRC_WAITER :
312                      {
313                                crc_manager.write_crc_file(NET_CRC_FILENAME);       // return 0 on failure
314                                client_type=1;                                  // confirmation byte
315                                new_sock->write(&client_type,1);
316                                delete new_sock;                                // done with this socket now
317                                delete addr;
318                      } break;
319                      case CLIENT_LSF_WAITER :          // wants to know which .lsp file to start with
320                      {
321                                uint8_t len=strlen(lsf);
322                                new_sock->write(&len,1);
323                                new_sock->write(lsf,len);
324                                delete new_sock;
325                                delete addr;
326                      } break;
327                      default :
328                      {
329                                if (game_face->add_client(client_type,new_sock,addr)==0)  // ask server or client to add new client
330                                {
331                                  delete addr;
332                                  delete new_sock;
333                                }
334                      } break;
335                    }
336                  }
337                }
338      }
339      if (!game_face->process_net())
340      {
341                delete game_face;
342                game_face=new game_handler;
343      }
344      fman->process_net();
345    }
346  }
347}
348
349
350int get_remote_lsf(net_address *addr, char *filename)  // filename should be 256 bytes
351{
352  if (prot)
353  {
354    net_socket *sock=prot->connect_to_server(addr,net_socket::SOCKET_SECURE);
355    if (!sock) return 0;
356
357    uint8_t ctype=CLIENT_LSF_WAITER;
358    uint8_t len;
359
360    if (sock->write(&ctype,1)!=1 ||
361                sock->read(&len,1)!=1 || len==0 ||
362                sock->read(filename,len)!=len)
363    {
364      delete sock;
365      return 0;
366    }
367
368    delete sock;
369    return 1;
370
371  } else return 0;
372}
373
374void server_check() { ; }
375
376int request_server_entry()
377{
378  if (prot && main_net_cfg)
379  {
380    if (!net_server) return 0;
381
382    if (game_sock) delete game_sock;
383    dprintf("Joining game in progress, hang on....\n");
384
385    game_sock=prot->create_listen_socket(main_net_cfg->port+2,net_socket::SOCKET_FAST);     // this is used for fast game packet transmission
386    if (!game_sock) { if (comm_sock) delete comm_sock; comm_sock=NULL; prot=NULL; return 0; }
387    game_sock->read_selectable();
388
389    net_socket *sock=prot->connect_to_server(net_server,net_socket::SOCKET_SECURE);
390    if (!sock)
391    {
392      fprintf(stderr,"unable to connect to server\n");
393      return 0;
394    }
395
396    uint8_t ctype=CLIENT_ABUSE;
397    uint16_t port=lstl(main_net_cfg->port+2),cnum;
398
399    uint8_t reg;
400    if (sock->write(&ctype,1)!=1 ||   // send server out game port
401                sock->read(&reg,1)!=1)        // is remote engine registered?
402    { delete sock; return 0; }
403
404    if (reg==2)   // too many players
405    {
406      fprintf(stderr, "%s", symbol_str("max_players"));
407      delete sock;
408      return 0;
409    }
410
411    // make sure the server is registered or sync problems will occur
412    if (!reg)
413    {
414      fprintf(stderr, "%s", symbol_str("server_not_reg"));
415      delete sock;
416      return 0;
417    }
418
419    char uname[256];
420    if (get_login())
421      strcpy(uname,get_login());
422    else strcpy(uname,"unknown");
423    uint8_t len=strlen(uname)+1;
424    short nkills;
425
426    if (sock->write(&len,1)!=1 ||
427                sock->write(uname,len)!=len ||
428                sock->write(&port,2)!=2  ||            // send server out game port
429                sock->read(&port,2)!=2   ||            // read server's game port
430                sock->read(&nkills,2)!=2 ||
431                sock->read(&cnum,2)!=2   || cnum==0    // read player number (cannot be 0 because 0 is server)
432                )
433    { delete sock; return 0; }
434
435    nkills=lstl(nkills);
436    port=lstl(port);
437    cnum=lstl(cnum);
438
439    main_net_cfg->kills=nkills;
440    net_address *addr=net_server->copy();
441    addr->set_port(port);
442
443    delete game_face;
444    game_face=new game_client(sock,addr);
445    delete addr;
446
447    local_client_number=cnum;
448    return cnum;
449  } else return 0;
450}
451
452int reload_start()
453{
454  if (prot)
455    return game_face->start_reload();
456  else return 0;
457}
458
459int reload_end()
460{
461  if (prot)
462    return game_face->end_reload();
463  else return 0;
464}
465
466
467void net_reload()
468{
469  if (prot)
470  {
471    if (net_server)
472    {
473      if (current_level)
474        delete current_level;
475      bFILE *fp;
476
477      if (!reload_start()) return ;
478
479      do {            // make sure server saves the file
480                fp=open_file(NET_STARTFILE,"rb");
481                if (fp->open_failure()) { delete fp; fp=NULL; }
482      } while (!fp);
483
484      spec_directory sd(fp);
485
486#if 0
487      spec_entry *e=sd.find("Copyright 1995 Crack dot Com, All Rights reserved");
488      if (!e)
489      {
490                the_game->show_help("This level is missing copyright information, cannot load\n");
491                current_level=new level(100,100,"untitled");
492                the_game->need_refresh();
493      }
494      else
495#endif
496        current_level=new level(&sd,fp,NET_STARTFILE);
497
498      delete fp;
499      base->current_tick=(current_level->tick_counter()&0xff);
500
501      reload_end();
502    } else if (current_level)
503    {
504
505      join_struct *join_list=base->join_list;
506
507
508      while (join_list)
509      {
510
511                view *f=player_list;
512                for (; f && f->next; f=f->next);      // find last player, add one for pn
513                int i,st=0;
514                for (i=0; i<total_objects; i++)
515                if (!strcmp(object_names[i],"START"))
516                st=i;
517
518                game_object *o=create(current_start_type,0,0);
519                game_object *start=current_level->get_random_start(320,NULL);
520                if (start) { o->x=start->x; o->y=start->y; }
521                else { o->x=100; o->y=100; }
522
523                f->next=new view(o,NULL,join_list->client_id);
524                strcpy(f->next->name,join_list->name);
525                o->set_controller(f->next);
526                f->next->set_tint(f->next->player_number);
527                if (start)
528                current_level->add_object_after(o,start);
529                else
530                current_level->add_object(o);
531
532                view *v=f->next;
533
534                v->cx1=5;
535                v->cy1=5;
536                v->cx2=319-5;
537                v->cy2=199-5;
538                join_list=join_list->next;
539      }
540      base->join_list=NULL;
541      current_level->save(NET_STARTFILE,1);
542      base->mem_lock=0;
543
544
545      Jwindow *j=wm->new_window(0,yres/2,-1,-1,new info_field(0, 0, 0, symbol_str("resync"),
546                          new button(0, wm->font()->height() + 5, ID_NET_DISCONNECT,
547                             symbol_str("slack"),NULL)),symbol_str("hold!"))
548;
549
550
551
552      wm->flush_screen();
553      if (!reload_start()) return ;
554
555      base->input_state=INPUT_RELOAD;    // if someone missed the game tick with the RELOAD data in it, make sure the get it
556
557      // wait for all client to reload the level with the new players
558      do
559      {
560                service_net_request();
561                if (wm->event_waiting())
562                {
563                  event ev;
564                  do
565                  {
566                    wm->get_event(ev);
567                    if (ev.type==EV_MESSAGE && ev.message.id==ID_NET_DISCONNECT)
568                    {
569                      game_face->end_reload(1);
570                      base->input_state=INPUT_PROCESSING;
571                    }
572
573                  } while (wm->event_waiting());
574
575                  wm->flush_screen();
576                }
577
578      } while (!reload_end());
579      wm->close_window(j);
580      unlink(NET_STARTFILE);
581
582      the_game->reset_keymap();
583
584      base->input_state=INPUT_COLLECTING;
585
586    }
587  }
588}
589
590
591int client_number() { return local_client_number; }
592
593
594void send_local_request()
595{
596
597  if (prot)
598  {
599    if (current_level)
600      base->current_tick=(current_level->tick_counter()&0xff);
601    game_face->add_engine_input();
602  } else base->input_state=INPUT_PROCESSING;
603
604}
605
606
607void kill_slackers()
608{
609  if (prot)
610  {
611    if (!game_face->kill_slackers())
612    {
613      delete game_face;
614      game_face=new game_handler();
615    }
616  }
617}
618
619int get_inputs_from_server(unsigned char *buf)
620{
621  if (prot && base->input_state!=INPUT_PROCESSING)      // if input is not here, wait on it
622  {
623    time_marker start;
624
625    int total_retry=0;
626    Jwindow *abort=NULL;
627
628    while (base->input_state!=INPUT_PROCESSING)
629    {
630      if (!prot)
631      {
632    base->input_state=INPUT_PROCESSING;
633    return 1;
634      }
635      service_net_request();
636
637      time_marker now;                   // if this is taking to long, the packet was probably lost, ask for it to be resent
638
639      if (now.diff_time(&start)>0.05)
640      {
641    if (prot->debug_level(net_protocol::DB_IMPORTANT_EVENT))
642      fprintf(stderr,"(missed packet)");
643
644
645    game_face->input_missing();
646    start.get_time();
647
648    total_retry++;
649    if (total_retry==12000)    // 2 minutes and nothing
650    {
651      abort=wm->new_window(0,yres/2,-1,wm->font()->height()*4,
652                   new info_field(0, 0, 0, symbol_str("waiting"),
653                          new button(0, wm->font()->height() + 5, ID_NET_DISCONNECT,
654                             symbol_str("slack"),NULL)),symbol_str("Error"));
655      wm->flush_screen();
656    }
657      }
658      if (abort)
659      {
660    if (wm->event_waiting())
661    {
662      event ev;
663      do
664      {
665        wm->get_event(ev);
666        if (ev.type==EV_MESSAGE && ev.message.id==ID_NET_DISCONNECT)
667        {
668          kill_slackers();
669          base->input_state=INPUT_PROCESSING;
670        }
671      } while (wm->event_waiting());
672
673      wm->flush_screen();
674    }
675      }
676    }
677
678    if (abort)
679    {
680      wm->close_window(abort);
681      the_game->reset_keymap();
682
683    }
684  }
685
686
687  memcpy(base->last_packet.data,base->packet.data,base->packet.packet_size()+base->packet.packet_prefix_size());
688
689  int size=base->packet.packet_size();
690  memcpy(buf,base->packet.packet_data(),size);
691
692  base->packet.packet_reset();
693  base->mem_lock=0;
694
695  return size;
696}
697
698int become_server(char *name)
699{
700  if (prot && main_net_cfg)
701  {
702    delete game_face;
703
704    if (comm_sock) delete comm_sock;
705    comm_sock=prot->create_listen_socket(main_net_cfg->port,net_socket::SOCKET_SECURE);   // this is used for incomming connections
706    if (!comm_sock) { prot=NULL; return 0; }
707    comm_sock->read_selectable();
708        prot->start_notify(0x9090, name, strlen(name));  // should we define a new socket for notifiers?
709
710    if (game_sock) delete game_sock;
711    game_sock=prot->create_listen_socket(main_net_cfg->port+1,net_socket::SOCKET_FAST);     // this is used for fast game packet transmission
712    if (!game_sock) { if (comm_sock) delete comm_sock; comm_sock=NULL; prot=NULL; return 0; }
713    game_sock->read_selectable();
714
715    game_face=new game_server;
716    local_client_number=0;
717    return 1;
718  }
719  return 0;
720}
721
722void read_new_views() { ; }
723
724
725void wait_min_players()
726{
727  if (game_face) game_face->game_start_wait();
728}
Note: See TracBrowser for help on using the repository browser.