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

Last change on this file since 682 was 682, checked in by Sam Hocevar, 8 years ago

core: rename vec2i to ivec2 and update matrix.h from Lol Engine.

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