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

Last change on this file since 645 was 645, checked in by Sam Hocevar, 9 years ago

imlib: clean up EventHandler? and JCMouse.

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