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

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