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

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