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

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

core: Get rid of mostly useless headers, move endianness handling to
common.h (and rewrite functions so that they do not need the SDL headers)
and move a few functions out of sdlport's video.cpp. These functions
were in the original video.cpp (which reappears) and shouldn't be part
of the SDL port.

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