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

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

ps3: make everything compile on the PS3. Of course, nothing links yet
because so much support is missing.

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