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

Last change on this file since 106 was 106, checked in by Sam Hocevar, 15 years ago
  • Rename the "eh" variable to "wm" because it's a window manager, not an event handler.
  • No longer pass the window manager to functions, there's only one.

Inspired by Win32 Abuse changelog for January 28, 2001:

  • Starting work on singleton code; will get rid of all

references to an arbitrary window_manager* because
there's only going to be one, and it's not ever
going to change.

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