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

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

imlib: use vec2i for image::size and unroll all necessary changes
everywhere else in the code.

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