source: abuse/trunk/src/net/gserver.cpp @ 56

Last change on this file since 56 was 56, checked in by Sam Hocevar, 11 years ago
  • Add licensing terms to most C / C++ files (Ref #5).
File size: 11.2 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#include <stdlib.h>
14#include <fcntl.h>
15#include <unistd.h>
16#include <sys/stat.h>
17#include <sys/types.h>
18#include <string.h>
19#include <signal.h>
20
21#include "system.h"
22#include "macs.hpp"
23#include "gserver.hpp"
24#include "netface.hpp"
25#include "timing.hpp"
26#include "netcfg.hpp"
27#include "id.hpp"
28#include "jwindow.hpp"
29#include "input.hpp"
30#include "dev.hpp"
31
32extern base_memory_struct *base;
33extern net_socket *comm_sock,*game_sock;
34extern int registered;
35
36extern net_protocol *prot;
37extern join_struct *join_array;
38extern window_manager *eh;
39extern void service_net_request();
40
41game_server::game_server()
42{
43        player_list = NULL;
44        waiting_server_input = 1;
45        reload_state = 0;
46}
47
48int game_server::total_players()
49{
50        player_client *fl = player_list;
51        int total = 1;
52        for( ; fl; fl = fl->next)
53        {
54                total++;
55        }
56        return total;
57}
58
59void game_server::game_start_wait()
60{
61  int last_count=0;
62  jwindow *stat=NULL;
63  event ev;
64  int abort=0;
65  while (!abort && total_players()<main_net_cfg->min_players)
66  {
67    if (last_count!=total_players())
68    {
69      if (stat) eh->close_window(stat);
70      char msg[100];
71      sprintf(msg,symbol_str("min_wait"),main_net_cfg->min_players-total_players());
72      stat=eh->new_window(100,50,-1,-1,new info_field(WINDOW_FRAME_LEFT,WINDOW_FRAME_TOP,ID_NULL,msg,
73                                       new button(WINDOW_FRAME_LEFT,WINDOW_FRAME_TOP+eh->font()->height()*2,
74                                                  ID_CANCEL,symbol_str("cancel_button"),NULL)  ));
75      eh->flush_screen();
76      last_count=total_players();
77    }
78
79    if (eh->event_waiting())
80    {
81      do { eh->get_event(ev); }  while (ev.type==EV_MOUSE_MOVE && eh->event_waiting());
82      eh->flush_screen();
83      if (ev.type==EV_MESSAGE && ev.message.id==ID_CANCEL)
84        abort=1;
85    }
86   
87    service_net_request();
88  }
89  if (stat)
90  {
91    eh->close_window(stat);
92    eh->flush_screen(); 
93  }
94}
95 
96game_server::player_client::~player_client()
97{
98  delete comm;
99  delete data_address;
100}
101
102void game_server::check_collection_complete()
103{
104  player_client *c;
105  int got_all=waiting_server_input==0;
106  int add_deletes=0;
107  for (c=player_list;c && got_all;c=c->next)
108  {
109    if (c->delete_me())
110      add_deletes=1;
111    else if (c->has_joined() && c->wait_input())
112      got_all=0;
113  }
114
115  if (add_deletes)
116  {
117    player_client *last=NULL;
118    for (c=player_list;c;)
119    {
120      if (c->delete_me())
121      {
122        base->packet.write_uint8(SCMD_DELETE_CLIENT);
123        base->packet.write_uint8(c->client_id);
124        if (c->wait_reload())
125        {
126          c->set_wait_reload(0);
127          check_reload_wait();
128        }
129
130        if (last) last->next=c->next;
131        else player_list=c->next;
132        player_client *d=c;
133        c=c->next;
134        delete d;
135      } else
136      {
137        last=c;
138        c=c->next;
139      }
140    }
141  }
142
143  if (got_all)    // see if we have input from everyone, if so send it out
144  {   
145    base->packet.calc_checksum();
146
147    for (c=player_list;c;c=c->next)      // setup for next time, wait for all the input
148    {
149      if (c->has_joined())
150      {
151        c->set_wait_input(1);     
152        game_sock->write(base->packet.data,base->packet.packet_size()+base->packet.packet_prefix_size(),c->data_address);
153
154      }
155    }
156
157    base->input_state=INPUT_PROCESSING; // tell engine to start processing
158    game_sock->read_unselectable();    // don't listen to this socket until we are prepared to read next tick's game data
159    waiting_server_input=1;
160  } 
161}
162
163void game_server::add_engine_input()
164{
165  waiting_server_input=0;
166  base->input_state=INPUT_COLLECTING;
167  base->packet.set_tick_received(base->current_tick);
168  game_sock->read_selectable();    // we can listen for game data now that we have server input
169  check_collection_complete();
170}
171
172void game_server::add_client_input(char *buf, int size, player_client *c)
173{
174  if (c->wait_input())  // don't add if we already have it
175  {
176    base->packet.add_to_packet(buf,size);
177    c->set_wait_input(0);
178    check_collection_complete();
179  }
180}
181
182void game_server::check_reload_wait()
183{
184  player_client *d=player_list;
185  for (;d;d=d->next)
186   if (d->wait_reload()) return ;    // we are still waiting for someone to reload the game
187  base->wait_reload=0;
188}
189
190int game_server::process_client_command(player_client *c)
191{
192  uint8_t cmd;
193  if (c->comm->read(&cmd,1)!=1) return 0;
194  switch (cmd)
195  {
196    case CLCMD_REQUEST_RESEND :
197    {
198      uint8_t tick;
199      if (c->comm->read(&tick,1)!=1) return 0;
200
201      fprintf(stderr,"request for resend tick %d (game cur=%d, pack=%d, last=%d)\n",
202              tick,base->current_tick,base->packet.tick_received(),base->last_packet.tick_received());
203
204      if (tick==base->last_packet.tick_received())
205      {
206        net_packet *pack=&base->last_packet;     
207        game_sock->write(pack->data,pack->packet_size()+pack->packet_prefix_size(),c->data_address);
208      }
209      return 1;
210    } break;
211    case CLCMD_RELOAD_START :
212    {
213      if (reload_state)   // already in reload state, notify client ok to start reloading
214      {
215        if (c->comm->write(&cmd,1)!=1)
216          c->set_delete_me(1);
217      } else c->set_need_reload_start_ok(1);
218      return 1;
219    } break;
220
221    case CLCMD_RELOAD_END :
222    {
223      c->set_wait_reload(0);
224      return 1;
225    } break;
226    case CLCMD_UNJOIN :
227    {
228      c->comm->write(&cmd,1);        // don't care weither this works or not
229      c->set_delete_me(1);
230      if (base->input_state==INPUT_COLLECTING)
231        check_collection_complete();
232    } break;
233  }
234  return 0;
235}
236
237
238int game_server::process_net()
239{
240  int ret=0;
241  /**************************       Any game data waiting?       **************************/
242  if ((base->input_state==INPUT_COLLECTING ||
243       base->input_state==INPUT_RELOAD)
244       && game_sock->ready_to_read())
245  {
246    net_packet tmp;
247    net_packet *use=&tmp;
248    net_address *from;
249    int bytes_received=game_sock->read(use->data,PACKET_MAX_SIZE,&from);
250
251    if (from && bytes_received)
252    {
253      // make sure we got a complete packet and the packet was not a previous game tick packet
254      if (bytes_received==use->packet_size()+use->packet_prefix_size())
255      {
256        uint16_t rec_crc=use->get_checksum();
257        if (rec_crc==use->calc_checksum())
258        {
259          player_client *f=player_list,*found=NULL;
260          for (;!found &&f;f=f->next)
261          if (f->has_joined() && from->equal(f->data_address))
262            found=f;
263          if (found)
264          {
265            if (base->current_tick==use->tick_received())           
266            {
267              if (prot->debug_level(net_protocol::DB_MINOR_EVENT))
268                fprintf(stderr,"(got data from %d)",found->client_id);
269
270//            fprintf(stderr,"(got packet %d)\n",use->tick_received());
271//            { time_marker now,start; while (now.diff_time(&start)<5.0) now.get_time(); }
272
273              if (base->input_state!=INPUT_RELOAD)
274                add_client_input((char *)use->packet_data(),use->packet_size(),found);
275
276            }
277            else if (use->tick_received()==base->last_packet.tick_received())
278            {
279              if (prot->debug_level(net_protocol::DB_IMPORTANT_EVENT))
280                fprintf(stderr,"(sending old %d)\n",use->tick_received());           
281
282              // if they are sending stale data we need to send them the last packet so they can catchup
283              net_packet *pack=&base->last_packet;     
284              game_sock->write(pack->data,pack->packet_size()+pack->packet_prefix_size(),found->data_address);
285
286            } else if (prot->debug_level(net_protocol::DB_MAJOR_EVENT))
287              fprintf(stderr,"received stale packet (got %d, expected %d)\n",use->tick_received(),base->current_tick);
288
289          } else
290          {
291            if (prot->debug_level(net_protocol::DB_MAJOR_EVENT))
292            {
293              fprintf(stderr,"received data from unknown client\n");
294              printf("from address "); from->print();
295              printf(" first addr "); player_list->data_address->print(); printf("\n");
296            }
297          }
298
299        } else fprintf(stderr,"received packet with bad checksum\n");
300      } else fprintf(stderr,"received incomplete packet\n");
301    } else if (!from)
302      fprintf(stderr,"received data and no from\n");
303    else if (!bytes_received)
304      fprintf(stderr,"received 0 byte data\n");
305    ret=1;
306    if (from) delete from;
307
308  }
309
310
311  /**************************       Any client with commands?       **************************/
312  player_client *c;
313  for (c=player_list;c;c=c->next) 
314    if (c->comm->error() || (c->comm->ready_to_read() && !process_client_command(c)))
315    {
316      c->set_delete_me(1);
317      check_collection_complete();
318    }
319    else ret=1;
320 
321  return 1;
322}
323
324
325int game_server::input_missing()
326{
327
328  return 1;
329}
330
331
332
333int game_server::end_reload(int disconnect)  // notify evryone you've reloaded the level (at server request)
334
335  player_client *c=player_list;
336  prot->select(0);
337
338  for (;c;c=c->next)
339    if (!c->delete_me() && c->wait_reload())
340    {
341      if (disconnect)
342        c->set_delete_me(1);
343      else return 0;
344    }
345
346  for (c=player_list;c;c=c->next)   
347    c->set_has_joined(1);
348  reload_state=0;
349 
350  return 1;
351}
352
353int game_server::start_reload()
354{
355  player_client *c=player_list;
356  reload_state=1;
357  prot->select(0);
358
359  for (;c;c=c->next)
360  {
361    if (!c->delete_me() && c->need_reload_start_ok())    // if the client is already waiting for reload state to start, send ok
362    {
363      uint8_t cmd=CLCMD_RELOAD_START;
364      if (c->comm->write(&cmd,1)!=1) { c->set_delete_me(1); }
365      c->set_need_reload_start_ok(0);
366    }
367    c->set_wait_reload(1);
368  }
369  return 1;
370}
371
372
373int game_server::isa_client(int client_id)
374{
375  player_client *c=player_list;
376  if (!client_id) return 1;
377  for (;c;c=c->next) if (c->client_id==client_id) return 1;
378  return 0;   
379}
380
381int game_server::add_client(int type, net_socket *sock, net_address *from)
382{
383        if( type == CLIENT_ABUSE )
384        {
385                if( total_players() >= main_net_cfg->max_players )
386                {
387                        uint8_t too_many = 2;
388                        sock->write( &too_many, 1 );
389                        return 0;
390                }
391
392                uint8_t reg = registered ? 1 : 0;
393                if( sock->write( &reg, 1 ) != 1 )
394                        return 0;
395
396                uint16_t our_port = lstl( main_net_cfg->port + 1 ), cport;
397                char name[256];
398                uint8_t len;
399                int16_t nkills=lstl(main_net_cfg->kills);
400
401                if( sock->read(&len,1)!=1 ||
402                        sock->read(name,len)!=len ||
403                        sock->read(&cport,2)!=2 ||
404                        sock->write(&our_port,2)!=2 ||
405                        sock->write(&nkills,2)!=2)
406                {
407                        return 0;
408                }
409
410                cport=lstl(cport);
411
412                int f = -1, i;
413                for( i = 0; f == -1 && i < MAX_JOINERS; i++ )
414                {
415                        if( !isa_client(i) )
416                        {
417                                f = i;
418                                join_struct *j=base->join_list;
419                                for( ; j; j = j->next )
420                                {
421                                        if( j->client_id == i )
422                                                f = -1;
423                                }
424                        }
425                }
426
427                if( f == -1 )
428                        return 0;
429
430                from->set_port( cport );
431
432                uint16_t client_id = lstl( f );
433                if( sock->write( &client_id, 2 ) != 2 )
434                {
435                        return 0;
436                }
437                client_id=f;
438
439                join_array[client_id].next = base->join_list;
440                base->join_list = &join_array[client_id];
441                join_array[client_id].client_id = client_id;
442                strcpy( join_array[client_id].name, name );
443                player_list = new player_client( f, sock, from, player_list );
444
445                return 1;
446        }
447        else
448        {
449                return 0;
450        }
451}
452
453int game_server::kill_slackers()
454{
455  player_client *c=player_list;
456  for (;c;c=c->next)
457    if (c->wait_input())
458      c->set_delete_me(1);
459  check_collection_complete(); 
460  return 1;
461}
462
463int game_server::quit()
464{
465  player_client *c=player_list;
466  while (c)
467  {
468    player_client *d=c;
469    c=c->next;
470    delete d;
471  }
472  player_list=NULL;
473  return 1;
474}
475
476
477game_server::~game_server()
478{
479        quit();
480}
481
Note: See TracBrowser for help on using the repository browser.