source: abuse/tags/pd/abuse/src/net/unix/gserver.c @ 49

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