Logo Search packages:      
Sourcecode: abuse-sdl version File versions  Download package

gserver.cpp

#include "system.h"
#include "macs.hpp"
#include "gserver.hpp"
#include "netface.hpp"
#include "timing.hpp"
#include "netcfg.hpp"
#include "id.hpp"
#include "jwindow.hpp"
#include "input.hpp"

extern base_memory_struct *base;
extern net_socket *comm_sock,*game_sock;
extern int registered;

extern net_protocol *prot;
extern join_struct *join_array;
extern window_manager *eh;
extern char *symbol_str(char *name);
extern void service_net_request();

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <signal.h>


game_server::game_server()
{
      player_list = NULL;
      waiting_server_input = 1;
      reload_state = 0;
}

int game_server::total_players()
{
      player_client *fl = player_list;
      int total = 1;
      for( ; fl; fl = fl->next)
      {
            total++;
      }
      return total;
}

void game_server::game_start_wait()
{
  int last_count=0;
  jwindow *stat=NULL;
  event ev;
  int abort=0;
  while (!abort && total_players()<main_net_cfg->min_players)
  {
    if (last_count!=total_players())
    {
      if (stat) eh->close_window(stat);
      char msg[100];
      sprintf(msg,symbol_str("min_wait"),main_net_cfg->min_players-total_players());
      stat=eh->new_window(100,50,-1,-1,new info_field(WINDOW_FRAME_LEFT,WINDOW_FRAME_TOP,ID_NULL,msg,
                               new button(WINDOW_FRAME_LEFT,WINDOW_FRAME_TOP+eh->font()->height()*2,
                                      ID_CANCEL,symbol_str("cancel_button"),NULL)  ));
      eh->flush_screen();
      last_count=total_players();
    }

    if (eh->event_waiting())
    {
      do { eh->get_event(ev); }  while (ev.type==EV_MOUSE_MOVE && eh->event_waiting()); 
      eh->flush_screen();
      if (ev.type==EV_MESSAGE && ev.message.id==ID_CANCEL)
        abort=1;
    }
    
    service_net_request();
  }
  if (stat)
  {
    eh->close_window(stat);
    eh->flush_screen();  
  }
}
  
game_server::player_client::~player_client()
{
  delete comm;
  delete data_address;
}

void game_server::check_collection_complete()
{
  player_client *c;
  int got_all=waiting_server_input==0;
  int add_deletes=0;
  for (c=player_list;c && got_all;c=c->next)
  {
    if (c->delete_me())
      add_deletes=1;
    else if (c->has_joined() && c->wait_input())
      got_all=0;
  }

  if (add_deletes)
  {
    player_client *last=NULL;
    for (c=player_list;c;)
    {
      if (c->delete_me())
      {
      base->packet.write_byte(SCMD_DELETE_CLIENT);
      base->packet.write_byte(c->client_id);
      if (c->wait_reload())
      {
        c->set_wait_reload(0);
        check_reload_wait();
      }

      if (last) last->next=c->next;
      else player_list=c->next;
      player_client *d=c;
      c=c->next;
      delete d;
      } else 
      {
      last=c;
      c=c->next;
      }
    }
  }

  if (got_all)    // see if we have input from everyone, if so send it out
  {   
    base->packet.calc_checksum();

    for (c=player_list;c;c=c->next)      // setup for next time, wait for all the input
    {
      if (c->has_joined())
      {
      c->set_wait_input(1);      
      game_sock->write(base->packet.data,base->packet.packet_size()+base->packet.packet_prefix_size(),c->data_address);

      }
    }

    base->input_state=INPUT_PROCESSING; // tell engine to start processing
    game_sock->read_unselectable();    // don't listen to this socket until we are prepared to read next tick's game data
    waiting_server_input=1;
  }  
}

void game_server::add_engine_input()
{
  waiting_server_input=0;
  base->input_state=INPUT_COLLECTING;
  base->packet.set_tick_received(base->current_tick);
  game_sock->read_selectable();    // we can listen for game data now that we have server input
  check_collection_complete();
}

void game_server::add_client_input(char *buf, int size, player_client *c)
{
  if (c->wait_input())  // don't add if we already have it
  {
    base->packet.add_to_packet(buf,size);
    c->set_wait_input(0);
    check_collection_complete();
  }
}

void game_server::check_reload_wait()
{
  player_client *d=player_list;
  for (;d;d=d->next) 
   if (d->wait_reload()) return ;    // we are still waiting for someone to reload the game 
  base->wait_reload=0;
}

int game_server::process_client_command(player_client *c)
{
  uchar cmd;
  if (c->comm->read(&cmd,1)!=1) return 0;
  switch (cmd)
  {
    case CLCMD_REQUEST_RESEND :
    {
      uchar tick;
      if (c->comm->read(&tick,1)!=1) return 0;

      fprintf(stderr,"request for resend tick %d (game cur=%d, pack=%d, last=%d)\n",
            tick,base->current_tick,base->packet.tick_received(),base->last_packet.tick_received());

      if (tick==base->last_packet.tick_received())
      {
      net_packet *pack=&base->last_packet;      
      game_sock->write(pack->data,pack->packet_size()+pack->packet_prefix_size(),c->data_address); 
      }
      return 1;
    } break;
    case CLCMD_RELOAD_START :
    {
      if (reload_state)   // already in reload state, notify client ok to start reloading
      {
        if (c->comm->write(&cmd,1)!=1) 
        c->set_delete_me(1);
      } else c->set_need_reload_start_ok(1);
      return 1;
    } break;

    case CLCMD_RELOAD_END :
    {
      c->set_wait_reload(0);
      return 1;
    } break;
    case CLCMD_UNJOIN :
    {
      c->comm->write(&cmd,1);        // don't care weither this works or not
      c->set_delete_me(1);
      if (base->input_state==INPUT_COLLECTING)
        check_collection_complete();
    } break;
  }
  return 0;
}


int game_server::process_net()
{
  int ret=0;
  /**************************       Any game data waiting?       **************************/
  if ((base->input_state==INPUT_COLLECTING ||
       base->input_state==INPUT_RELOAD)
       && game_sock->ready_to_read())
  {
    net_packet tmp;
    net_packet *use=&tmp;
    net_address *from;
    int bytes_received=game_sock->read(use->data,PACKET_MAX_SIZE,&from);

    if (from && bytes_received)
    {
      // make sure we got a complete packet and the packet was not a previous game tick packet
      if (bytes_received==use->packet_size()+use->packet_prefix_size())
      {
      unsigned short rec_crc=use->get_checksum();
      if (rec_crc==use->calc_checksum())
      {
        player_client *f=player_list,*found=NULL;
        for (;!found &&f;f=f->next)
        if (f->has_joined() && from->equal(f->data_address))
          found=f;
        if (found)
        {
          if (base->current_tick==use->tick_received())         
          {
            if (prot->debug_level(net_protocol::DB_MINOR_EVENT))
              fprintf(stderr,"(got data from %d)",found->client_id);

//          fprintf(stderr,"(got packet %d)\n",use->tick_received()); 
//          { time_marker now,start; while (now.diff_time(&start)<5.0) now.get_time(); } 

            if (base->input_state!=INPUT_RELOAD)
              add_client_input((char *)use->packet_data(),use->packet_size(),found);

          }
          else if (use->tick_received()==base->last_packet.tick_received())
          {
            if (prot->debug_level(net_protocol::DB_IMPORTANT_EVENT))
              fprintf(stderr,"(sending old %d)\n",use->tick_received());            

            // if they are sending stale data we need to send them the last packet so they can catchup
            net_packet *pack=&base->last_packet;      
            game_sock->write(pack->data,pack->packet_size()+pack->packet_prefix_size(),found->data_address); 

          } else if (prot->debug_level(net_protocol::DB_MAJOR_EVENT))
            fprintf(stderr,"received stale packet (got %d, expected %d)\n",use->tick_received(),base->current_tick);

        } else
        {
          if (prot->debug_level(net_protocol::DB_MAJOR_EVENT))
          {
            fprintf(stderr,"received data from unknown client\n");
            printf("from address "); from->print();
            printf(" first addr "); player_list->data_address->print(); printf("\n");
          }
        }

      } else fprintf(stderr,"received packet with bad checksum\n");
      } else fprintf(stderr,"received incomplete packet\n");
    } else if (!from)
      fprintf(stderr,"received data and no from\n");
    else if (!bytes_received)
      fprintf(stderr,"received 0 byte data\n");
    ret=1;
    if (from) delete from;

  }


  /**************************       Any client with commands?       **************************/
  player_client *c;
  for (c=player_list;c;c=c->next)  
    if (c->comm->error() || (c->comm->ready_to_read() && !process_client_command(c)))
    {
      c->set_delete_me(1);
      check_collection_complete();
    }
    else ret=1;
  
  return 1;
}


int game_server::input_missing()
{

  return 1;
}



int game_server::end_reload(int disconnect)  // notify evryone you've reloaded the level (at server request)
{  
  player_client *c=player_list;
  prot->select(0);

  for (;c;c=c->next) 
    if (!c->delete_me() && c->wait_reload()) 
    {
      if (disconnect)
        c->set_delete_me(1);
      else return 0;
    }

  for (c=player_list;c;c=c->next)   
    c->set_has_joined(1);
  reload_state=0;
  
  return 1;
}

int game_server::start_reload()
{
  player_client *c=player_list;
  reload_state=1;
  prot->select(0);

  for (;c;c=c->next) 
  {
    if (!c->delete_me() && c->need_reload_start_ok())    // if the client is already waiting for reload state to start, send ok
    {
      uchar cmd=CLCMD_RELOAD_START;
      if (c->comm->write(&cmd,1)!=1) { c->set_delete_me(1); }
      c->set_need_reload_start_ok(0);
    }
    c->set_wait_reload(1);
  }
  return 1;
}


int game_server::isa_client(int client_id)
{
  player_client *c=player_list;
  if (!client_id) return 1;
  for (;c;c=c->next) if (c->client_id==client_id) return 1;
  return 0;   
}

int game_server::add_client(int type, net_socket *sock, net_address *from)
{
      if( type == CLIENT_ABUSE )
      {
            if( total_players() >= main_net_cfg->max_players )
            {
                  uchar too_many = 2;
                  sock->write( &too_many, 1 );
                  return 0;
            }

            uchar reg = registered ? 1 : 0;
            if( sock->write( &reg, 1 ) != 1 )
                  return 0;

            ushort our_port = lstl( main_net_cfg->port + 1 ), cport;
            char name[256];
            uchar len;
            short nkills=lstl(main_net_cfg->kills);

            if( sock->read(&len,1)!=1 ||
                  sock->read(name,len)!=len ||
                  sock->read(&cport,2)!=2 ||
                  sock->write(&our_port,2)!=2 ||
                  sock->write(&nkills,2)!=2)
            {
                  return 0;
            }

            cport=lstl(cport);

            int f = -1, i;
            for( i = 0; f == -1 && i < MAX_JOINERS; i++ )
            {
                  if( !isa_client(i) )
                  {
                        f = i;
                        join_struct *j=base->join_list;
                        for( ; j; j = j->next )
                        {
                              if( j->client_id == i )
                                    f = -1;
                        }
                  }
            }

            if( f == -1 )
                  return 0;

            from->set_port( cport );

            ushort client_id = lstl( f );
            if( sock->write( &client_id, 2 ) != 2 )
            {
                  return 0;
            }
            client_id=f;

            join_array[client_id].next = base->join_list;
            base->join_list = &join_array[client_id];
            join_array[client_id].client_id = client_id;
            strcpy( join_array[client_id].name, name );
            player_list = new player_client( f, sock, from, player_list );

            return 1;
      }
      else
      {
            return 0;
      }
}

int game_server::kill_slackers()
{
  player_client *c=player_list;
  for (;c;c=c->next)
    if (c->wait_input())
      c->set_delete_me(1);
  check_collection_complete();  
  return 1;
}

int game_server::quit()
{
  player_client *c=player_list;
  while (c)
  {
    player_client *d=c;
    c=c->next;
    delete c;
  }
  player_list=NULL;
  return 1;
}


game_server::~game_server()
{
      quit();
}


Generated by  Doxygen 1.6.0   Back to index