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

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