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

Last change on this file since 111 was 111, checked in by Sam Hocevar, 11 years ago
  • Simplified the window creation arguments. Got rid of a lot of macros and hid stuff in private namespaces.

Inspired by Win32 Abuse changelog for January 28, 2001:

  • Well, in the process of adding changes necessary to

handle recovery from alt-tabbing away from Abuse
(which is why I was updating jwindow::redraw()),
the entire windowing system is getting an overhaul.
It's gonna be sweet when I'm done, though.

  • jwindow::redraw() has been changed to a virtual

function requiring no parameters. This'll make
it much easier to implement special specific-
purpose windows.

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