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

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