Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
netclient.cpp
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15  */
16 
17 /*
18  * NetClient - Network Client Interface - written by Stephane Vaxelaire <svax@free.fr>
19  */
20 #include "config.h"
21 #include "networking/netclient.h"
23 
24 #include <iostream>
25 #include <stdio.h>
26 #if !defined (WIN32)
27 #include <unistd.h>
28 #endif
29 
30 #include "gfx/background.h" //Background::BackgroundCache
31 
32 #include "vs_globals.h"
33 #include "endianness.h"
34 #include "cmd/unit_generic.h"
35 #include "cmd/unit_util.h"
36 #include "cmd/unit_const_cache.h"
37 #include "configxml.h"
38 #include "networking/client.h"
39 #include "networking/const.h"
41 #include "universe_util.h"
42 #include "cmd/unit_factory.h"
43 #include "gfx/matrix.h"
44 #include "load_mission.h"
45 #include "lin_time.h"
46 #include "vsfilesystem.h"
47 #include "cmd/role_bitmask.h"
48 #include "cmd/base_util.h"
49 #include "gfx/cockpit_generic.h"
50 #include "savenet_util.h"
51 #include "save_util.h"
52 
53 #include "cmd/pilot.h"
54 #include "cmd/ai/communication.h"
55 #include "cmd/ai/order.h"
56 
61 #include "vegastrike.h"
62 #include "networking/client.h"
64 #include "networking/networkcomm.h"
65 #include "posh.h"
66 #include "networking/prediction.h"
67 #include "fileutil.h"
68 #include "faction_generic.h"
69 
70 #include "netversion.h"
72 
73 using std::cout;
74 using std::endl;
75 using std::cin;
76 
77 double NETWORK_ATOM;
78 
80 typedef vector< Client* >::iterator VC;
81 typedef vector< ObjSerial >::iterator ObjI;
82 
83 extern const Unit * getUnitFromUpgradeName( const string &upgradeName, int myUnitFaction = 0 );
84 extern int GetModeFromName( const char* ); //1=add, 2=mult, 0=neither.
85 static const string LOAD_FAILED = "LOAD_FAILED";
86 extern Cargo * GetMasterPartList( const char *input_buffer );
87 extern bool isWeapon( std::string name );
88 
89 /*
90  ************************************************************
91  **** Tool functions ***
92  ************************************************************
93  */
94 
95 vector< ObjSerial >localSerials;
96 bool isLocalSerial( ObjSerial sernum )
97 {
98  //COUT<<"Looking for serial : "<<sernum<<" in ";
99  bool ret = false;
100  for (ObjI i = localSerials.begin(); !ret && i != localSerials.end(); i++)
101  //COUT<<(*i)<<", ";
102  if ( sernum == (*i) )
103  ret = true;
104  //COUT<<endl;
105 
106  return ret;
107 }
108 
110 {
111  for (unsigned int i = 0; i < _Universe->numPlayers(); i++)
112  if (Network[i].getUnit()->GetSerial() == cserial)
113  return Network[i].getUnit();
114  return NULL;
115 }
117 {
118  deltatime = 0;
119  game_unit = NULL;
120  latest_timestamp = 0;
121  keeprun = 1;
122  //old_time = 0;
123  cur_time = getNewTime();
124  enabled = 0;
125  nbclients = 0;
126  jumpok = false;
127  ingame = false;
128 #ifdef CRYPTO
129  FileUtil::use_crypto = true;
130 #endif
131 
132  NetComm = NULL;
133  lastsave.resize( 0 );
134  //_downloadManagerClient.reset( new VsnetDownload::Client::Manager( _sock_set ) );
135  //_sock_set.addDownloadManager( _downloadManagerClient );
136  _serverip = "";
137  _serverport = 0;
138  callsign = password = "";
139  this->Clients = ClientsMap();
140 
141  delete clt_tcp_sock;
142  clt_tcp_sock = new SOCKETALT;
143  //leave UDP well-enough alone
144 }
146 {
147  keeprun = 1;
148  clt_tcp_sock = new SOCKETALT;
149  clt_udp_sock = new SOCKETALT;
150  deltatime = 0;
151  game_unit = NULL;
152  latest_timestamp = 0;
153  //old_time = 0;
154  cur_time = getNewTime();
155  enabled = 0;
156  nbclients = 0;
157  jumpok = false;
158  ingame = false;
159 #ifdef CRYPTO
160  FileUtil::use_crypto = true;
161 #endif
162 
163  NetComm = NULL;
164 
165  _downloadManagerClient.reset( new VsnetDownload::Client::Manager( _sock_set ) );
166  _sock_set.addDownloadManager( _downloadManagerClient );
167 
168 #ifdef CRYPTO
169  cout<<endl<<endl<<POSH_GetArchString()<<endl;
170 #endif
171 }
172 
174 {
175  if (NetComm != NULL) {
176  delete NetComm;
177  NetComm = NULL;
178  }
179  if (clt_tcp_sock) delete clt_tcp_sock; //UDP sockets don't seem to like being deleted.
180  //if (clt_udp_sock) { delete clt_udp_sock; }
181 }
182 
183 /*
184  ************************************************************
185  **** Login loop ***
186  ************************************************************
187  */
188 
189 int NetClient::checkAcctMsg()
190 {
191  std::string packeta;
192  AddressIP ipadr;
193  int ret = 0;
194  //Watch account server socket
195  //Get the number of active clients
196  if ( acct_sock->isActive() ) {
197  //COUT<<"Net activity !"<<endl;
198  //Receive packet and process according to command
199  if ( acct_sock->recvstr( packeta ) != false && packeta.length() ) {
200  ret = 1;
201  std::string netbuf = packeta;
202  std::string warning;
203  switch ( getSimpleChar( netbuf ) )
204  {
205  case ACCT_LOGIN_DATA:
206  {
207  COUT<<">>> LOGIN DATA --------------------------------------"<<endl;
208  //We received game server info (the one we should connect to)
209  getSimpleString( netbuf ); //uname
210  string warning = getSimpleString( netbuf ); //message
211  this->error_message = warning;
212  _serverip = getSimpleString( netbuf );
213  string srvportstr = getSimpleString( netbuf );
214  const char *srvport = srvportstr.c_str();
215  int porttemp = atoi( srvport );
216  if (porttemp > 65535) porttemp = 0;
217  if (porttemp < 0) porttemp = 0;
218  this->_serverport = (unsigned short) porttemp;
219  COUT<<"<<< LOGIN DATA --------------------------------------"<<endl;
220  break;
221  }
222  case ACCT_LOGIN_ERROR:
223  COUT<<">>> LOGIN ERROR =( DENIED )= --------------------------------------"<<endl;
224  lastsave.resize( 0 );
225  getSimpleString( netbuf ); //uname
226  warning = getSimpleString( netbuf ); //message
227  lastsave.push_back( "" );
228  if ( !warning.empty() )
229  lastsave.push_back( warning );
230  else
231  lastsave.push_back( "Failed to login with this password!" );
232  break;
233  case ACCT_LOGIN_ALREADY:
234  COUT<<">>> LOGIN ERROR =( ALREADY LOGGED IN )= --------------------------------------"<<endl;
235  lastsave.resize( 0 );
236  getSimpleString( netbuf ); //uname
237  warning = getSimpleString( netbuf ); //message
238  lastsave.push_back( "" );
239  if ( !warning.empty() )
240  lastsave.push_back( warning );
241  else
242  lastsave.push_back( "The account is already logged in to a server!" );
243  break;
244  default:
245  COUT<<">>> UNKNOWN COMMAND =( "<<std::hex<<packeta<<std::dec<<" )= --------------------------------------"
246  <<std::endl;
247  lastsave.resize( 0 );
248  lastsave.push_back( "" );
249  lastsave.push_back( "!!! PROTOCOL ERROR : Unexpected command received !!!" );
250  }
251  } else {
252  char str[127];
253  sprintf( str, "!!! NETWORK ERROR : Connection to account server lost (error number %d)!!!",
254 #ifdef _WIN32
255  WSAGetLastError()
256 #else
257  errno
258 #endif
259  );
260  cerr<<str;
261 //lastsave.push_back( "");
262 //lastsave.push_back( str);
263  //acct_sock.disconnect( __PRETTY_FUNCTION__, false );
264  }
265  }
266  return ret;
267 }
268 
269 /*
270  ************************************************************
271  **** Launch the client ***
272  ************************************************************
273  */
274 
275 /*
276  * extern bool cleanexit;
277  *
278  * void NetClient::start( char * addr, unsigned short port)
279  * {
280  * COUT << " enter " << __PRETTY_FUNCTION__
281  * << " with " << addr << ":" << port << endl;
282  *
283  * keeprun = 1;
284  *
285  * cout<<"Initializing network connection..."<<endl;
286  * string nettransport;
287  * nettransport = vs_config->getVariable( "network", "transport", "udp" );
288  * if( nettransport == "tcp" )
289  * {
290  * this->clt_sock = NetUITCP::createSocket( addr, port, _sock_set );
291  * }
292  * else
293  * {
294  * this->clt_sock = NetUIUDP::createSocket( addr, port, _sock_set );
295  * }
296  * if (!this->clt_sock) {
297  * perror( "Error creating socket ");
298  * cleanexit=true;
299  * VSExit(1);
300  * }
301  * if( this->authenticate() == -1)
302  * {
303  * perror( "Error login in ");
304  * cleanexit=true;
305  * VSExit(1);
306  * }
307  *
308  * cout<<"Initiating client loop"<<endl;
309  * while( keeprun)
310  * {
311  * this->checkKey();
312  * this->checkMsg( NULL );
313  * micro_sleep( 30000);
314  * }
315  *
316  * this->disconnect();
317  * }
318  *
319  * void NetClient::checkKey()
320  * {
321  * }
322  */
323 
324 /*
325  *************************************************************
326  **** Check if its is time to get network messages ***
327  *************************************************************
328  */
329 
330 //This function is made to decide whether it is time to check
331 //network messages or not... depending on how often we want to
332 //do so.
333 //For now, it is always time to receive network messages
334 
335 void NetClient::versionBuf( NetBuffer &buf ) const
336 {
337  buf.setVersion( this->netversion );
338 }
339 
341 {
342  int ret = 0;
343  //COUT<<"cur_time="<<cur_time<<" - elapsed="<<GetElapsedTime()<<endl;
344  if ( (getNewTime()-cur_time) > NETWORK_ATOM ) {
345  cur_time = getNewTime();
346  ret = 1;
347  }
348  return ret;
349 }
350 
351 /*
352  *************************************************************
353  **** Send packets to server ***
354  *************************************************************
355  */
356 
357 //void NetClient::sendMsg()
358 //{
359 //}
360 
361 /*
362  *************************************************************
363  **** Check if server has sent something ***
364  *************************************************************
365  */
366 
367 int NetClient::checkMsg( Packet *outpacket )
368 {
369  int ret = 0;
370  string jpeg_str( "" );
371  timeval tv;
372  tv.tv_sec = 0;
373  tv.tv_usec = 0;
374  if ( clt_tcp_sock->isActive() || clt_udp_sock->isActive() )
375  ret = recvMsg( outpacket, &tv );
376  if (ret == -1) {
377  NetClient::CleanUp(); //Kill networking!!!
378  UniverseUtil::startMenuInterface( false, "Connection to VegaServer closed." );
379  return -1;
380  }
381  //If we have network communications enabled and webcam support enabled we grab an image
382  if ( NetComm != NULL && NetComm->IsActive() )
383  //Here also send samples
384  NetComm->SendSound( *this->clt_tcp_sock, this->serial );
385  return ret;
386 }
387 
388 #include "lowlevel/vsnet_err.h"
389 extern void SwitchUnits2( Unit *un );
390 void NetClient::Respawn( ObjSerial newserial )
391 {
392  unsigned int whichcp;
393  for (whichcp = 0; whichcp < _Universe->numPlayers(); ++whichcp)
394  if (_Universe->AccessCockpit( whichcp )->GetParent() == NULL)
395  break;
396  if ( whichcp == _Universe->numPlayers() ) {
397  whichcp = 0;
398  cerr<<"Error could not find blank cockpit to respawn into\n";
399  }
400  QVector pos( 0, 0, 0 );
401  bool setplayerXloc;
402  string mysystem;
403  Cockpit *cp = _Universe->AccessCockpit( whichcp );
404  vector< string > packedInfo;
405 
406  static float initialzoom = XMLSupport::parse_float( vs_config->getVariable( "graphics", "inital_zoom_factor", "2.25" ) );
407  cp->zoomfactor = initialzoom;
408  cp->savegame->SetStarSystem( mysystem );
409  cp->savegame->ParseSaveGame( "",
410  mysystem,
411  "",
412  pos,
413  setplayerXloc,
414  cp->credits,
415  packedInfo,
416  whichcp,
417  lastsave[0],
418  false );
419  string fullsysname = mysystem+".system";
420  StarSystem *ss;
421 
422  cp->UnpackUnitInfo(packedInfo);
423 
424  {
425  Background::BackgroundClone savedtextures = {
426  {NULL, NULL, NULL, NULL, NULL, NULL, NULL}
427  };
428  Background *tmp = NULL;
429  if ( _Universe->activeStarSystem() ) {
431  savedtextures = tmp->Cache();
432  }
434  ss = _Universe->GenerateStarSystem( fullsysname.c_str(), "", Vector( 0, 0, 0 ) );
435  if (tmp)
436  savedtextures.FreeClone();
437  }
439  unsigned int oldcp = _Universe->CurrentCockpit();
441  std::string unkeyname = cp->GetUnitFileName();
442  int fgsnumber = 0;
443  if (cp->fg) {
444  fgsnumber = cp->fg->flightgroup_nr++;
445  cp->fg->nr_ships++;
446  cp->fg->nr_ships_left++;
447  }
448  Unit *un = UnitFactory::createUnit( unkeyname.c_str(), false, FactionUtil::GetFactionIndex(
449  cp->savegame->GetPlayerFaction() ), std::string(
450  "" ), cp->fg, fgsnumber, &lastsave[1], newserial );
451  un->SetSerial( newserial );
452  //fighters[a]->faction = FactionUtil::GetFactionIndex( cp->savegame->GetPlayerFaction());
453  cp->SetParent( un, unkeyname.c_str(), "", pos );
454  un->SetPosAndCumPos( pos );
455  this->game_unit.SetUnit( un );
456  localSerials.push_back( newserial );
457  ss->AddUnit( un );
458  AddClientObject( un, newserial );
459  SwitchUnits2( un );
460  cp->SetView( CP_FRONT );
462  _Universe->SetActiveCockpit( oldcp );
465 }
466 /*
467  *************************************************************
468  **** Receive a message from the server ***
469  *************************************************************
470  */
471 extern bool preEmptiveClientFire( const weapon_info* );
472 int NetClient::recvMsg( Packet *outpacket, timeval *timeout )
473 {
474  /* // Returns false if no data hasarrived on the socket.
475  * // Required if you only want to poll.
476  * if( !clt_sock.isActive( ) ) {
477  * return 0;
478  * }
479  */
480  using namespace VSFileSystem;
481  ObjSerial packet_serial = 0;
482 
483  static vector< Mount::STATUS >backupMountStatus;
484 
485  //Receive data
486  Unit *un = NULL;
487  unsigned int mount_num;
488  ObjSerial mis = 0;
489  ObjSerial local_serial = 0;
490  if (this->game_unit.GetUnit() != NULL)
491  local_serial = this->game_unit.GetUnit()->GetSerial();
492  Cockpit *cp;
493 
494  Packet p1;
495  AddressIP ipadr;
496 /*
497  * // Restart game!!!
498  * _Universe->Loop(bootstrap_first_loop);*/
499  static bool udpgetspriority = true;
500  bool wasudp = udpgetspriority;
501 
502  //First check if there is data in the client's recv queue.
503  int recvbytes = (udpgetspriority ? clt_udp_sock : clt_tcp_sock)->recvbuf( &p1, &ipadr );
504  if (recvbytes <= 0) {
505  recvbytes = (udpgetspriority == false ? clt_udp_sock : clt_tcp_sock)->recvbuf( &p1, &ipadr );
506  wasudp = !udpgetspriority;
507  }
508  if (recvbytes <= 0) {
509  //Now, select and wait for data to come in the queue.
510  clt_tcp_sock->addToSet( _sock_set );
511  clt_udp_sock->addToSet( _sock_set );
512  int socketstat = _sock_set.wait( timeout );
513  if ( !clt_tcp_sock->valid() ) {
514  perror( "Error socket closed " );
515  clt_tcp_sock->disconnect( "socket error closed" );
516  //NETFIXME: Error handling on socket error? Exit?
517  return -1;
518  }
519  if (socketstat < 0) {
520  perror( "Error select -1 " );
521  clt_tcp_sock->disconnect( "socket error recv err" );
522  return -1;
523  }
524  if (socketstat == 0)
525 //COUT << "recvMsg socketstat == 0: " << (vsnetEWouldBlock()?"wouldblock":"") << endl;
526  return -1;
527  //timeout expired.
528 
529  //NETFIXME: check for file descriptors in _sock_set.fd_set...
530  //Check the queues again.
531  recvbytes = (udpgetspriority ? clt_udp_sock : clt_tcp_sock)->recvbuf( &p1, &ipadr );
532  wasudp = udpgetspriority;
533  if (recvbytes <= 0) {
534  recvbytes = (udpgetspriority == false ? clt_udp_sock : clt_tcp_sock)->recvbuf( &p1, &ipadr );
535  wasudp = !udpgetspriority;
536  }
537  udpgetspriority = !udpgetspriority;
538  if (recvbytes <= 0) {
539  //If nothing has come in either queue, and the select did not return 0, then this must be from a socket error.
540  perror( "Error recv -1 " );
541  clt_tcp_sock->disconnect( "socket error recv" );
542  return -1;
543  }
544  }
545  if (true) {
546  //p1.getDataLength()>0) {
547 
548  bool nostarsystem = _Universe->activeStarSystem() == NULL ? true : false;
549 
550  _Universe->netLock( true ); //Don't bounce any commands back to the server again!
551 
552  NetBuffer netbuf( p1.getData(), p1.getDataLength() );
553  versionBuf( netbuf );
554  if (outpacket)
555  *outpacket = p1;
556  packet_serial = p1.getSerial();
557  Cmd cmd = p1.getCommand();
558  if (cmd != CMD_SNAPSHOT)
559  COUT<<"Rcvd "<<(wasudp ? "UDP" : "TCP")<<": "<<cmd<<" from serial "<<packet_serial<<endl;
560  switch (cmd)
561  {
562  //Login accept
563  case CMD_CONNECT:
564  {
565  ObjSerial server_netversion = netbuf.getSerial();
566  this->netversion = server_netversion;
567  string ipaddress = netbuf.getString();
568  cout<<"Connection by "<<CLIENT_NETVERSION<<" to "
569  <<"VegaServer "<<server_netversion<<" from address "<<ipaddress<<endl;
570  if (server_netversion > CLIENT_NETVERSION) {
571  cout<<"Using old client... setting version to "<<CLIENT_NETVERSION<<endl;
572  this->netversion = CLIENT_NETVERSION;
573  } else if (server_netversion < CLIENT_NETVERSION) {
574  cout<<"Connected to an old server. Setting version to "<<server_netversion<<endl;
575  }
576  break;
577  }
578  case CMD_CHOOSESHIP:
579  this->loginChooseShip( p1 );
580  break;
581  case LOGIN_ACCEPT:
582  this->loginAccept( p1 );
583  break;
584  case CMD_ASKFILE:
585  {
586  //NETFIXME: Broken code... shouldn't write to client's stuff
587  //Also, shouldn't open files Read-only and then write to them.
588  //Also it shouldn't exit(1)...
589  string filename;
590  string file;
591  filename = netbuf.getString();
592  file = netbuf.getString();
593  //If packet serial == 0 then it means we have an up to date file
594  if (packet_serial == local_serial) {
595  //Receive the file and write it (trunc if exists)
596  cerr<<"RECEIVING file : "<<filename<<endl;
597  VSFile f;
598  VSError err = f.OpenReadOnly( filename, ::VSFileSystem::UnknownFile );
599  if (err > Ok) {
600  cerr<<"!!! ERROR : opening received file !!!"<<endl;
601  VSExit( 1 );
602  }
603  if ( f.Write( file ) != file.length() ) {
604  cerr<<"!!! ERROR : writing received file !!!"<<endl;
605  VSExit( 1 );
606  }
607  f.Close();
608  } else {
609  //Something is wrong
610  //displayError( packet_serial);
611  }
612  break;
613  }
614  case CMD_DOWNLOAD:
615  COUT<<endl;
616  if (_downloadManagerClient)
617  _downloadManagerClient->processCmdDownload( *clt_tcp_sock, netbuf );
618  break;
619  //Login failed
620  case LOGIN_ERROR:
621  COUT<<">>> LOGIN ERROR =( DENIED )= ------------------------------------------------"<<endl;
622  this->disconnect();
623  lastsave.push_back( "" );
624  lastsave.push_back( "!!! ACCESS DENIED : Account does not exist with this password !!!" );
625  return -1;
626 
627  break;
628  case LOGIN_UNAVAIL:
629  COUT<<">>> ACCOUNT SERVER UNAVAILABLE ------------------------------------------------"<<endl;
630  lastsave.push_back( "" );
631  lastsave.push_back( "!!! ACCESS DENIED : Account server unavailable !!!" );
632  this->disconnect();
633  return -1;
634 
635  break;
636  //Create a character
637  case CMD_CREATECHAR:
638  COUT<<endl;
639  //Should begin character/ship creation process
640  //this->createChar();
641  break;
642  //Receive start locations
643  case CMD_LOCATIONS:
644  COUT<<endl;
645  //Should receive possible starting locations list
646  this->receiveLocations( &p1 );
647  break;
648  case CMD_TXTMESSAGE:
649  {
650  string sender = netbuf.getString();
651  string message = netbuf.getString();
652  UniverseUtil::IOmessage( 0, sender, "all", message );
653  break;
654  }
655  case CMD_CUSTOM:
656  {
657  un = this->game_unit.GetUnit();
658  int cp = _Universe->whichPlayerStarship( un );
659  string cmd = netbuf.getString();
660  string args = netbuf.getString();
661  string id = netbuf.getString();
662  UniverseUtil::receivedCustom( cp, true, cmd, args, id );
663  break;
664  }
665  case CMD_SNAPSHOT:
666  {
667  if (nostarsystem) break;
668  //Should update another client's position
669  //Zone hack:
670  //When receiving a snapshot, packet serial is considered as the
671  //number of client updates.
672  unsigned int numUnits = p1.getSerial();
673  unsigned int timestamp = p1.getTimestamp();
674  double deltatime = netbuf.getFloat();
675 
676 //COUT << " *** #units=" << numUnits << " ts=" << timestamp << " delta-t=" << deltatime << endl;
677 
678  this->receivePositions( numUnits, timestamp, netbuf, deltatime );
679  break;
680  }
681  case CMD_ENTERCLIENT:
682  if (nostarsystem) break;
683  //Saving 4 bytes for every 50kB saved game isn't worth the bugs that come with it.
684 //if (p1.getSerial()) {
685 //this->enterClient( netbuf, p1.getSerial() );
686 //} else {
687  this->AddObjects( netbuf );
688 //}
689  break;
690  case CMD_EXITCLIENT:
691  if (nostarsystem) break;
692  COUT<<">>> "<<local_serial<<" >>> EXITING CLIENT =( serial #"
693  <<packet_serial<<" )= --------------------------------------"<<endl;
694  this->removeClient( &p1 );
695  break;
696  case CMD_ADDEDYOU:
698  if (nostarsystem) break;
699  COUT<<">>> "<<local_serial<<" >>> ADDED IN GAME =( serial #"
700  <<packet_serial<<" )= --------------------------------------"<<endl;
701  //now we have to make the unit if it is null (this would be a respawn)
702  if (this->game_unit.GetUnit() == NULL)
703  this->Respawn( packet_serial );
704  this->game_unit.GetUnit()->curr_physical_state = netbuf.getTransformation();
705  break;
706  case CMD_DISCONNECT:
707  /*** TO REDO IN A CLEAN WAY ***/
708  COUT<<">>> "<<local_serial<<" >>> DISCONNECTED -> Client killed =( serial #"
709  <<packet_serial<<" )= --------------------------------------"<<endl;
710 
711  break;
712 //case CMD_ACK :
715 //COUT << ">>> ACK =( " << latest_timestamp
716 //<< " )= ---------------------------------------------------" << endl;
717 //p1.ack( );
718 //break;
719  case CMD_FIREREQUEST:
720  {
721  if (nostarsystem) break;
722  //WE RECEIVED A FIRE NOTIFICATION SO FIRE THE WEAPON
723  float energy = netbuf.getFloat();
724  mis = netbuf.getSerial();
725  mount_num = netbuf.getInt32();
726  //Find the unit
727  if (p1.getSerial() == local_serial) //WE have fired and receive the broadcast
728  un = this->game_unit.GetUnit();
729  else
730  un = UniverseUtil::GetUnitFromSerial( p1.getSerial() );
731  if (un != NULL) {
732  //Set the concerned mount as ACTIVE and others as INACTIVE
733  vector< Mount >
734  ::iterator i = un->mounts.begin(); //note to self: if vector<Mount *> is ever changed to vector<Mount> remove the const_ from the const_iterator
735  if ( mount_num > un->mounts.size() )
736  mount_num = un->mounts.size();
737  unsigned int j;
738 
739  un->energy = energy; //It's important to set energy before firing.
740  for (j = backupMountStatus.size(); j < un->mounts.size(); ++j)
741  backupMountStatus.push_back( Mount::UNCHOSEN );
742  for (j = 0; i != un->mounts.end(); ++i, ++j) {
743  backupMountStatus[j] = (*i).status;
744  if ( (*i).status == Mount::ACTIVE )
745  (*i).status = Mount::INACTIVE;
746  }
747  Cockpit *ps = _Universe->isPlayerStarship( un );
748  for (j = 0; j < mount_num; ++j) {
749  unsigned int mnt = (unsigned int)netbuf.getInt32();
750  if (mnt < un->mounts.size() && mnt >= 0) {
751  if ( ps == NULL || !preEmptiveClientFire( un->mounts[mnt].type ) ) {
752  un->mounts[mnt].processed = Mount::ACCEPTED;
753  un->mounts[mnt].status = Mount::ACTIVE;
754  //Store the missile id in the mount that should fire a missile
755  un->mounts[mnt].serial = mis;
756  }
757  }
758  }
759  //Ask for fire
760  if (mis != 0)
761  un->Fire( ROLES::FIRE_MISSILES|ROLES::EVERYTHING_ELSE, false );
762  else
763  un->Fire( ROLES::EVERYTHING_ELSE|ROLES::FIRE_GUNS, false );
764  i = un->mounts.begin();
765  for (j = 0; i != un->mounts.end(); ++i, ++j)
766  (*i).status = backupMountStatus[j];
767  } else {
768  COUT<<"!!! Problem -> CANNOT FIRE UNIT NOT FOUND !!!"<<endl;
769  }
770  break;
771  }
772  case CMD_UNFIREREQUEST:
773  if (nostarsystem) break;
774  //WE RECEIVED AN UNFIRE NOTIFICATION SO DEACTIVATE THE WEAPON
775  mount_num = netbuf.getInt32();
776 //mis = netbuf.getSerial();
777  //Find the unit
778  un = UniverseUtil::GetUnitFromSerial( p1.getSerial() );
779  if (un != NULL) {
780  //Set the concerned mount as ACTIVE and others as INACTIVE
781  vector< Mount >
782  ::iterator i = un->mounts.begin(); //note to self: if vector<Mount *> is ever changed to vector<Mount> remove the const_ from the const_iterator
783  unsigned int j;
784  if ( mount_num > un->mounts.size() )
785  mount_num = un->mounts.size();
786  for (j = backupMountStatus.size(); j < un->mounts.size(); ++j)
787  backupMountStatus.push_back( Mount::UNCHOSEN );
788  for (j = 0; i != un->mounts.end(); ++i, ++j) {
789  backupMountStatus[j] = (*i).status;
790  if ( (*i).status == Mount::ACTIVE )
791  (*i).status = Mount::INACTIVE;
792  }
793  for (j = 0; j < mount_num; ++j) {
794  unsigned int mnt = (unsigned int)netbuf.getInt32();
795  if (mnt < un->mounts.size() && mnt >= 0) {
796  un->mounts[mnt].processed = Mount::UNFIRED;
797  un->mounts[mnt].status = Mount::ACTIVE;
798  //Store the missile id in the mount that should fire a missile
799  un->mounts[mnt].serial = 0; //mis;
800  }
801  }
802  //Ask for fire
803  un->UnFire();
804 
805  i = un->mounts.begin();
806  for (j = 0; i != un->mounts.end(); ++i, ++j)
807  (*i).status = backupMountStatus[j];
808  } else {
809  COUT<<"!!! Problem -> CANNOT UNFIRE UNIT NOT FOUND !!!"<<endl;
810  }
811  break;
812  case CMD_TARGET:
813  if (nostarsystem) break;
814  un = UniverseUtil::GetUnitFromSerial( packet_serial );
815  if (un) {
816  unsigned short targserial = netbuf.getSerial();
817  Unit *target_un = UniverseUtil::GetUnitFromSerial( targserial );
818  if (target_un)
819  COUT<<"Confirmed targeting unit "<<target_un->name<<" ("<<targserial<<")."<<endl;
820  Unit *oldtarg = un->Target();
821  if ( oldtarg && oldtarg->GetSerial() == 0 && (target_un == NULL || target_un->GetSerial() == 0) )
822  COUT<<"Setting target from "<<oldtarg->name<<" to NULL."<<endl;
823  //don't do anything
824  else
825  un->computer.target.SetUnit( target_un );
826  }
827  break;
828  case CMD_SCAN:
829  if (nostarsystem) break;
830  //We received the target info with the target serial in the packet as an answer to a scanRequest
831 
832  //Update info with received buffer
833 
834  //And tell all VDUs we received the target info
835  cp = _Universe->isPlayerStarship( this->game_unit.GetUnit() );
836  cp->ReceivedTargetInfo();
837  break;
838  case CMD_SNAPDAMAGE:
839  {
840  if (nostarsystem) break;
841  //In case we use damage snapshots : we do not call ApplyNetDamage
842  //In fact we trusted the client only for visual FX : Check where they are done !
843  //but the server computes the damage itself
844 
845  //SHOULD READ THE DAMAGE SNAPSHOT HERE !
846  unsigned int nbupdates = packet_serial;
848  int offset = netbuf.getOffset();
849  for (unsigned int i = 0; i < nbupdates; i++) {
850  serial = netbuf.getSerial();
851  int noffset = netbuf.getOffset();
852  if (noffset == offset) {
853  COUT<<"ERROR Premature end of Snapshot buffer "<<std::hex<<std::string(
854  netbuf.getData(), netbuf.getSize() )<<std::dec<<std::endl;
855  break;
856  }
857  offset = noffset;
858  Unit *un = UniverseUtil::GetUnitFromSerial( serial );
859  receiveUnitDamage( netbuf, un );
860  }
861  break;
862  }
863 #if 1
864  case CMD_DAMAGE:
865  {
866  if (nostarsystem) break;
867  float amt = netbuf.getFloat();
868  float ppercentage = netbuf.getFloat();
869  float spercentage = netbuf.getFloat();
870  Vector pnt = netbuf.getVector();
871  Vector normal = netbuf.getVector();
872  GFXColor col = netbuf.getColor();
873  un = UniverseUtil::GetUnitFromSerial( p1.getSerial() );
874  float hul = netbuf.getFloat();
875  Shield sh = netbuf.getShield();
876  Armor ar = netbuf.getArmor();
877  if (un) {
878  if (un->hull >= 0) {
879  //Apply the damage
880  un->ApplyNetDamage( pnt, normal, amt, ppercentage, spercentage, col );
881  un->shield = sh;
882  un->armor = ar;
883  un->hull = hul;
884  }
885  if (un->hull < 0)
886  un->Destroy();
887  } else {
888  COUT<<"!!! Problem -> CANNOT APPLY DAMAGE UNIT NOT FOUND !!!"<<endl;
889  }
890  break;
891  }
892 #endif
893 #if 0
894  case CMD_DAMAGE1:
895  /*
896  * if (nostarsystem) break;
897  * float amt = netbuf.getFloat();
898  * float phasedamage = netbuf.getFloat();
899  * Vector pnt = netbuf.getVector();
900  * Vector normal = netbuf.getVector();
901  * GFXColor col = netbuf.getColor();
902  * un = UniverseUtil::GetUnitFromSerial( p1.getSerial());
903  * un->ApplyLocalDamage( pnt, normal, amt, NULL, col, phasedamage);
904  */
905  break;
906 #endif
907  case CMD_KILL:
908  {
909  if (nostarsystem) break;
910  ClientPtr clt = Clients.get( p1.getSerial() );
911  //If it is not a player
912  if (!clt) {
913  un = UniverseUtil::GetUnitFromSerial( p1.getSerial() );
914  if (un) {
915  un->Destroy();
916  un->Kill( true, true );
917  } else {
918  COUT<<"!!! Problem -> CANNOT KILL UNIT NOT FOUND !!!"<<endl;
919  }
920  } else {
921  un = clt->game_unit.GetUnit();
922  //Remove the player unit
923  nbclients--;
924  Clients.remove( p1.getSerial() );
925  if (un) {
926  un->Destroy();
927  } else {
928  un = UniverseUtil::GetUnitFromSerial( p1.getSerial() );
929  if (un) {
930  un->Destroy();
931  un->Kill( true, true );
932  }
933  }
934  COUT<<"Client #"<<p1.getSerial()<<" killed - now "<<nbclients<<" clients in system"<<endl;
935  if ( !clt->callsign.empty() ) {
936  string msg = clt->callsign+" has died.";
937  UniverseUtil::IOmessage( 0, "game", "all", "#FFFF66"+msg+"#000000" );
938  }
939  }
940  break;
941  }
942  case CMD_SAVEACCOUNTS:
943  {
944  Unit *un = this->game_unit.GetUnit();
945  if (un) {
946  int cpnum = _Universe->whichPlayerStarship( un );
947  if (cpnum >= 0 && this->lastsave.size() >= 2)
948  SaveNetUtil::GetSaveStrings( cpnum, lastsave[0], lastsave[1], true );
949  }
950  break;
951  }
952  case CMD_JUMP:
953  if (nostarsystem) break;
954  if (1) {
955  std::string srvipadr( netbuf.getString() );
956  unsigned short port( netbuf.getShort() );
957  //SetConfigServerAddress(srvipadr,port);
958  Reconnect( srvipadr, port );
959  } else {
960  //this is the old way of doing it
961  StarSystem *sts;
962  string newsystem = netbuf.getString();
963  ObjSerial unserial = netbuf.getSerial();
964  ObjSerial jumpserial = netbuf.getSerial();
965  unsigned short zoneid = netbuf.getShort();
966  un = this->game_unit.GetUnit();
967  if (!un)
968  break;
969  //Get the pointer to the new star system sent by server
970  if ( !( sts = star_system_table.Get( newsystem ) ) ) {
971  //The system should have been loaded just before we asked for the jump so this is just a safety check
972  cerr<<"!!! FATAL ERROR : Couldn't find destination Star system !!!"<<endl;
973  sts = _Universe->GenerateStarSystem( newsystem.c_str(), "", Vector( 0, 0, 0 ) );
974  }
975  //If unserial == un->GetSerial() -> then we are jumping otherwise it is another unit/player
976  if ( unserial == un->GetSerial() ) {
977  this->zone = zoneid;
978  //If we received a CMD_JUMP with serial==player serial jump is granted
979  if ( packet_serial == un->GetSerial() ) {
980  this->jumpok = true;
981  this->ingame = false;
982  }
983  //The jump has been allowed but we don't have the good system file
984  else {
985  //Here really do the jump function
986  Unit *jumpun = UniverseUtil::GetUnitFromSerial( jumpserial );
987  sts->JumpTo( un, jumpun, newsystem, true );
988  string sysfile( newsystem+".system" );
989  VsnetDownload::Client::NoteFile f( *this->clt_tcp_sock, sysfile, SystemFile );
990  _downloadManagerClient->addItem( &f );
991 
992  timeval timeout = {10, 0};
993  while ( !f.done() )
994  if (recvMsg( NULL, &timeout ) <= 0) {
995 //NETFIXME: What to do if the download times out?
996  COUT<<"recvMsg <=0: "<<(vsnetEWouldBlock() ? "wouldblock" : "")<<endl;
997  break;
998  }
999  this->jumpok = true;
1000  }
1001  } else {
1002  //If another player / unit is jumping force it
1003  Unit *jumpun = UniverseUtil::GetUnitFromSerial( jumpserial );
1004  sts->JumpTo( un, jumpun, newsystem, true );
1005  }
1006  }
1007  break;
1008  case CMD_SNAPCARGO:
1009  {
1010  if (nostarsystem) break;
1011  ObjSerial ser;
1013  while ( ( ser = netbuf.getSerial() ) != 0 ) {
1015  unsigned int i;
1016  //Clear cargo... back to front to make it more efficient.
1017  if (un) {
1018  i = un->numCargo();
1019  while (i > 0) {
1020  i--;
1021  un->RemoveCargo( i, un->GetCargo( i ).GetQuantity(), true );
1022  }
1023  }
1024  float mass = netbuf.getFloat();
1025  float cargvol = netbuf.getFloat();
1026  float upgvol = netbuf.getFloat();
1027  if (un) {
1028  un->Mass = mass;
1029  un->pImage->CargoVolume = cargvol;
1030  un->pImage->UpgradeVolume = upgvol;
1031  }
1032  unsigned int numcargo = (unsigned int)netbuf.getInt32();
1033  bool mission = false;
1034  if (numcargo < 0) {
1035  mission = true;
1036  numcargo = -numcargo;
1037  }
1038  Cargo carg;
1039  for (i = 0; i < numcargo; i++) {
1040  unsigned int mplind;
1041  unsigned int quantity = (unsigned int)netbuf.getInt32();
1042  string str = netbuf.getString();
1043  if (un) {
1044  Cargo *foundcarg = mpl->GetCargo( str.c_str(), mplind );
1045  if (foundcarg) {
1046  carg = *foundcarg;
1047  } else {
1048  //COUT << "Server sent bad cargo '"<<str<<"' for unit serial "<<ser<<endl;
1049  carg = Cargo();
1050  carg.SetContent( str );
1051  }
1052  }
1053  carg.SetQuantity( quantity );
1054  carg.SetPrice( netbuf.getFloat() );
1055  carg.SetMass( netbuf.getFloat() );
1056  carg.SetVolume( netbuf.getFloat() );
1057  if (un)
1058  un->AddCargo( carg, false );
1059  }
1060  }
1061  break;
1062  }
1063  case CMD_MISSION:
1064  {
1065  un = this->game_unit.GetUnit();
1066  int cp = _Universe->whichPlayerStarship( un );
1067  if (cp == -1) break;
1068  unsigned short type = netbuf.getShort();
1069  string qualname = netbuf.getString();
1070  int pos = netbuf.getInt32();
1071  if (type == Subcmd::TerminateMission) {
1072  Mission *activeMis = Mission::getNthPlayerMission( cp, pos+1 );
1073  if (activeMis)
1074  activeMis->terminateMission();
1075  else
1076  fprintf( stderr, "Failed to find and terminate mission %d for player %d\n", pos, cp );
1077  } else if (type == Subcmd::AcceptMission) {
1078  //lame duck mission
1079  unsigned int oldcp = _Universe->CurrentCockpit();
1080  _Universe->SetActiveCockpit( cp );
1082  while ( !Mission::getNthPlayerMission( cp, pos+1 ) )
1083  LoadMission( "", "import Director; temp=Director.Mission()", false );
1084  string::size_type tpos = qualname.find( '/' );
1085  string cat = qualname.substr( 0, tpos );
1086  active_missions.back()->mission_name = cat;
1088  _Universe->SetActiveCockpit( oldcp );
1089  }
1091  break;
1092  }
1093  case CMD_COMM:
1094  {
1095  if (nostarsystem) break;
1096  Unit *from = UniverseUtil::GetUnitFromSerial( packet_serial );
1097  Unit *to = game_unit.GetUnit();
1098  unsigned int curstate = netbuf.getInt32();
1099  if (!from) {
1100  COUT<<"Received invalid comm message "<<curstate<<" from "<<packet_serial<<endl;
1101  break;
1102  }
1103  if (!to) {
1104  COUT<<"Received comm message while dead."<<endl;
1105  break;
1106  }
1107  FSM *fsm = FactionUtil::GetConversation( to->faction, from->faction );
1108  if ( curstate >= 0 && curstate < fsm->nodes.size() ) {
1109  unsigned char sex = 0;
1110  if (from->pilot)
1111  sex = from->pilot->getGender();
1112  CommunicationMessage c( from, game_unit.GetUnit(), NULL, sex );
1113  c.SetCurrentState( curstate, NULL, sex );
1114  Order *oo = to->getAIState();
1115  if (oo)
1116  oo->Communicate( c );
1117  }
1118  //if not a valid new node (-1)
1119 
1120  factions[from->faction]->faction[to->faction].relationship = netbuf.getFloat();
1121  factions[to->faction]->faction[from->faction].relationship = netbuf.getFloat();
1122  float relfrompilot = netbuf.getFloat();
1123  float reltopilot = netbuf.getFloat();
1124  if (from->pilot) {
1125  Pilot::relationmap::iterator i = from->pilot->effective_relationship.find( to );
1126  if ( i != from->pilot->effective_relationship.end() )
1127  (*i).second = relfrompilot;
1128  }
1129  if (to->pilot) {
1130  Pilot::relationmap::iterator i = to->pilot->effective_relationship.find( from );
1131  if ( i != to->pilot->effective_relationship.end() )
1132  (*i).second = reltopilot;
1133  }
1134  break;
1135  }
1136  case CMD_CARGOUPGRADE:
1137  {
1138  if (nostarsystem) break;
1139  ObjSerial buyer_ser = netbuf.getSerial();
1140  ObjSerial seller_ser = netbuf.getSerial();
1141  int quantity = netbuf.getInt32();
1142  std::string cargoName = netbuf.getString();
1143  float price = netbuf.getFloat();
1144  float mass = netbuf.getFloat();
1145  float volume = netbuf.getFloat();
1146  int mountOffset = ( (int) netbuf.getInt32() );
1147  int subunitOffset = ( (int) netbuf.getInt32() );
1148  Unit *sender = UniverseUtil::GetUnitFromSerial( packet_serial );
1149  Unit *buyer = UniverseUtil::GetUnitFromSerial( buyer_ser );
1150  Unit *seller = UniverseUtil::GetUnitFromSerial( seller_ser );
1151  bool missioncarg = false;
1152 
1153  unsigned int cargIndex = 0;
1154  Cargo *cargptr = NULL;
1155  if (!sender)
1156  break;
1157  if (seller)
1158  cargptr = seller->GetCargo( cargoName, cargIndex );
1159  if (!cargptr) {
1160  cargptr = GetMasterPartList( cargoName.c_str() );
1161  if (!cargptr)
1162  break;
1163  }
1164  Cargo carg = *cargptr;
1165  bool upgrade = false;
1166  bool repair = false;
1167  bool weapon = false;
1168  if (carg.GetCategory().find( "upgrades" ) == 0) {
1169  upgrade = true;
1170  if ( isWeapon( carg.GetCategory() ) )
1171  weapon = true;
1172  else if (!quantity && buyer == sender)
1173  repair = true;
1174  }
1175  if (!upgrade)
1176  missioncarg = (mountOffset == 1 && subunitOffset == 1);
1177  carg.mass = mass;
1178  carg.price = price;
1179  carg.volume = volume;
1180  carg.mission = missioncarg;
1181  if (quantity) {
1182  if (buyer) {
1183  carg.SetQuantity( quantity );
1184  buyer->AddCargo( carg, true );
1185  }
1186  if (seller)
1187  seller->RemoveCargo( cargIndex, quantity, true );
1188  }
1189  if ( upgrade && !repair && (seller == sender || buyer == sender) ) {
1190  double percent; //not used.
1191  int multAddMode = GetModeFromName( carg.GetContent().c_str() );
1192 
1193  //Now we're sure it's an authentic upgrade...
1194  //Wow! So much code just to perform an upgrade!
1195  const string unitDir = GetUnitDir( sender->name.get().c_str() );
1196  string templateName;
1197  int faction = 0;
1198  if (seller == sender) {
1199  templateName = unitDir+".blank";
1200  faction = seller->faction;
1201  } else if (buyer == sender) {
1202  faction = buyer->faction;
1203  templateName = unitDir+".template";
1204  }
1205  const Unit *unitCarg = getUnitFromUpgradeName( carg.GetContent(), faction );
1206  if (!unitCarg) break; //not an upgrade, and already did cargo transactions.
1207  //Get the "limiter" for the upgrade. Stats can't increase more than this.
1208  const Unit *templateUnit = UnitConstCache::getCachedConst( StringIntKey( templateName, faction ) );
1209  if (!templateUnit) {
1210  templateUnit = UnitConstCache::setCachedConst( StringIntKey( templateName, faction ),
1211  UnitFactory::createUnit( templateName.c_str(), true,
1212  faction ) );
1213  }
1214  if (templateUnit->name == LOAD_FAILED)
1215  templateUnit = NULL;
1216  if (unitCarg->name == LOAD_FAILED)
1217  break;
1218  if (seller == sender) {
1219  //Selling it... Downgrade time!
1220  if ( seller->canDowngrade( unitCarg, mountOffset, subunitOffset, percent, templateUnit ) )
1221  seller->Downgrade( unitCarg, mountOffset, subunitOffset, percent, templateUnit );
1222  } else if (buyer == sender) {
1223  //Buying it... Upgrade time!
1224  if ( buyer->canUpgrade( unitCarg, mountOffset, subunitOffset, multAddMode, true, percent, templateUnit ) )
1225  buyer->Upgrade( unitCarg, mountOffset, subunitOffset, multAddMode, true, percent, templateUnit );
1226  }
1227  }
1228  if (repair)
1229  sender->RepairUpgradeCargo( &carg, seller, NULL );
1230  Unit *player = game_unit.GetUnit();
1231  if ( player
1232  && ( ( buyer
1233  && buyer->isDocked( player ) )
1234  || ( seller && seller->isDocked( player ) ) || player == buyer || player == seller ) )
1236  break;
1237  }
1238  case CMD_CREDITS:
1239  cp = _Universe->isPlayerStarship( this->game_unit.GetUnit() );
1240  if (cp)
1241  cp->credits = netbuf.getFloat();
1242  //BaseUtil::refreshBaseComputerUI(NULL);
1243  break;
1244  case CMD_SAVEDATA:
1245  {
1246  un = this->game_unit.GetUnit();
1247  int cp = _Universe->whichPlayerStarship( un );
1248  if (cp == -1) break;
1249  unsigned short type = netbuf.getShort();
1250  string key;
1251  string strValue;
1252  float floatValue = 0;
1253  int pos = 0;
1254  Mission *activeMis = NULL;
1255  Mission *origMis = mission;
1256  if ( (type&Subcmd::StringValue) || (type&Subcmd::FloatValue) )
1257  key = netbuf.getString();
1258  pos = netbuf.getInt32();
1259  if (type&Subcmd::Objective) {
1260  int missionnum = netbuf.getInt32();
1261  activeMis = Mission::getNthPlayerMission( cp, missionnum+1 );
1262  }
1263  if (activeMis == NULL) activeMis = mission;
1264  if (type&Subcmd::SetValue) {
1265  if (pos < 0) break; //-1 is valid for erasing.
1266  if ( (type&Subcmd::StringValue) || (type&Subcmd::Objective) )
1267  strValue = netbuf.getString();
1268  if ( (type&Subcmd::FloatValue) || (type&Subcmd::Objective) )
1269  floatValue = netbuf.getFloat();
1270  }
1271  switch (type)
1272  {
1273  case (Subcmd::FloatValue|Subcmd::SetValue):
1274  while (getSaveDataLength( cp, key ) <= (unsigned int) pos && (unsigned int) pos != UINT_MAX)
1275  pushSaveData( cp, key, 0 );
1276  putSaveData( cp, key, pos, floatValue );
1277  break;
1278  case (Subcmd::FloatValue|Subcmd::EraseValue):
1279  if (pos < 0)
1280  for (unsigned int i = getSaveDataLength( cp, key ); i > 0; i--)
1281  eraseSaveData( cp, key, (i-1) );
1282  else
1283  eraseSaveData( cp, key, pos );
1284  break;
1285  case (Subcmd::StringValue|Subcmd::SetValue):
1286  while (getSaveStringLength( cp, key ) <= (unsigned int) pos && (unsigned int) pos != UINT_MAX)
1287  pushSaveString( cp, key, "" );
1288  putSaveString( cp, key, pos, strValue );
1289  break;
1290  case (Subcmd::StringValue|Subcmd::EraseValue):
1291  if (pos < 0)
1292  for (unsigned int i = getSaveStringLength( cp, key ); i > 0; i--)
1293  eraseSaveString( cp, key, (i-1) );
1294  else
1295  eraseSaveString( cp, key, pos );
1296  break;
1297  case (Subcmd::Objective|Subcmd::SetValue):
1298  mission = activeMis;
1299  while (mission->objectives.size() <= (unsigned int) pos && (unsigned int) pos != UINT_MAX)
1301  UniverseUtil::setObjective( pos, strValue );
1302  UniverseUtil::setCompleteness( pos, floatValue );
1303  mission = origMis;
1304  BaseUtil::refreshBaseComputerUI( NULL ); //objectives
1305  break;
1306  case (Subcmd::Objective|Subcmd::EraseValue):
1307  mission = activeMis;
1308  if ( (unsigned int) pos < mission->objectives.size() && (unsigned int) pos >= 0 && (unsigned int) pos
1309  != UINT_MAX )
1310  mission->objectives.erase( activeMis->objectives.begin()+pos );
1311  else
1313  mission = origMis;
1314  BaseUtil::refreshBaseComputerUI( NULL ); //objetives
1315  break;
1316  }
1317  break;
1318  }
1319  case CMD_STARTNETCOMM:
1320 #ifdef NETCOMM
1321  {
1322  float freq = netbuf.getFloat();
1323  char secured = netbuf.getChar();
1324  char webc = netbuf.getChar();
1325  char pa = netbuf.getChar();
1326  if (freq == current_freq) {
1327  if ( secured == NetComm->IsSecured() ) {
1328  ClientPtr clt;
1329  //Check this is not us
1330  if (packet_serial != this->serial) {
1331  //Add the client to netcomm list in NetComm ?
1332  clt = Clients.get( packet_serial );
1333  clt->webcam = webc;
1334  clt->portaudio = pa;
1335  NetComm->AddToSession( clt );
1336  }
1337  } else {
1338  cerr<<"WARNING : Received a STARTCOMM from a channel not in the same mode"<<endl;
1339  }
1340  } else {
1341  cerr<<"WARNING : Received a STARTCOMM from another frequency"<<endl;
1342  }
1343  }
1344 #endif
1345  break;
1346  case CMD_STOPNETCOMM:
1347 #ifdef NETCOMM
1348  {
1349  ClientPtr clt;
1350  //Check this is not us
1351  if (packet_serial != this->serial) {
1352  //Remove the client to netcomm list in NetComm
1353  clt = Clients.get( packet_serial );
1354  NetComm->RemoveFromSession( clt );
1355  }
1356  }
1357 #endif
1358  break;
1359  case CMD_SOUNDSAMPLE:
1360 #ifdef NETCOMM
1361  {
1362  NetComm->RecvSound( p1.getData(), p1.getDataLength(), false );
1363  }
1364 #endif
1365  break;
1366  case CMD_SECSNDSAMPLE:
1367 #ifdef NETCOMM
1368  {
1369  NetComm->RecvSound( p1.getData(), p1.getDataLength(), true );
1370  }
1371 #endif
1372  break;
1373 #if 0
1374  //NETFIXME this is probably more consistent
1375  case CMD_TXTMESSAGE:
1376 #ifdef NETCOMM
1377  {
1378  string msg( p1.getData() );
1379  NetComm->RecvMessage( msg, false );
1380  }
1381 #endif
1382 #endif
1383  case CMD_SECMESSAGE:
1384 #ifdef NETCOMM
1385  {
1386  string msg( p1.getData() );
1387  NetComm->RecvMessage( msg, true );
1388  }
1389 #endif
1390  break;
1391  case CMD_DOCK:
1392  {
1393  if (nostarsystem) break;
1394  ObjSerial utdw_serial = netbuf.getSerial();
1395  un = UniverseUtil::GetUnitFromSerial( utdw_serial );
1396  //int dockport = netbuf.getInt32();
1397  unsigned int dockport;
1398  for (dockport = 0; dockport < un->pImage->dockingports.size(); ++dockport)
1399  if (!un->pImage->dockingports[dockport].IsOccupied())
1400  break;
1401  if ( dockport > un->pImage->dockingports.size() ) {
1402  cerr<<"CMD_DOCK: All docking ports used up! Kicking out port 0!"<<endl;
1403  dockport = 0;
1404  un->pImage->dockingports[0].Occupy(false);
1405  }
1406  cerr<<"RECEIVED A DOCK AUTHORIZATION for unit "<<p1.getSerial()<<" to unit "<<utdw_serial
1407  <<" at docking port #"<<dockport<<endl;
1408  Unit *un2 = UniverseUtil::GetUnitFromSerial( p1.getSerial() );
1409  un->RequestClearance( un2 );
1410  un2->ForceDock( un, dockport );
1411  break;
1412  }
1413  case CMD_UNDOCK:
1414  {
1415  if (nostarsystem) break;
1416  ObjSerial utdw_serial = netbuf.getSerial();
1417  cerr<<"RECEIVED A UNDOCK ORDER for unit "<<p1.getSerial()<<" to unit "<<utdw_serial<<endl;
1418  un = UniverseUtil::GetUnitFromSerial( utdw_serial );
1419  Unit *un2 = UniverseUtil::GetUnitFromSerial( p1.getSerial() );
1420  un2->UnDock( un );
1421  break;
1422  }
1423  case CMD_POSUPDATE:
1424  {
1425  if (nostarsystem) break;
1426  //If a client receives that it means the server want to force the client position to be updated
1427  //with server data
1428  ClientState serverpos = netbuf.getClientState();
1429  un = this->game_unit.GetUnit();
1430  if (!un)
1431  break;
1432  un->old_state = serverpos;
1433  serverpos.setUnitState( un );
1434  un->BackupState();
1435  break;
1436  }
1437  case CMD_SERVERTIME:
1438  break;
1439  default:
1440  COUT<<">>> "<<local_serial<<" >>> UNKNOWN COMMAND =( "<<std::hex<<cmd
1441  <<" )= --------------------------------------"<<std::endl;
1442  keeprun = 0;
1443  this->disconnect();
1444  }
1445  _Universe->netLock( false );
1446  }
1447  return recvbytes;
1448 }
1449 
1450 /*
1451  ************************************************************
1452  **** Disconnect from the server ***
1453  ************************************************************
1454  */
1455 
1456 void NetClient::disconnect()
1457 {
1458  keeprun = 0;
1459  //Disconnection is handled in the VSExit(1) function for each player
1460  //Or, if you don't actually want to exit(1), you can logout with:
1461  logout( true );
1462 }
1463 
1464 SOCKETALT* NetClient::logout( bool leaveUDP )
1465 {
1466  keeprun = 0;
1467  Packet p;
1468  if (clt_tcp_sock->valid() && clt_tcp_sock->get_fd() != -1) {
1469  Unit *un = this->game_unit.GetUnit();
1470  if (un) {
1471  p.send( CMD_LOGOUT, un->GetSerial(),
1472  (char*) NULL, 0,
1473  SENDRELIABLE, NULL, *this->clt_tcp_sock,
1474  __FILE__, PSEUDO__LINE__( 1382 ) );
1475  timeval tv = {10, 0};
1476  recvMsg( &p, &tv );
1477  }
1478  clt_tcp_sock->disconnect( "Closing connection to server" );
1479  }
1480  Mission *mis;
1481  //Can't figure out how to get cockpit number?
1482  while ( ( mis = Mission::getNthPlayerMission( (this-Network), 0 ) ) )
1483  mis->terminateMission();
1484  if (!leaveUDP)
1485  NetUIUDP::disconnectSaveUDP( *clt_udp_sock );
1486 //clt_udp_sock->disconnect( "Closing UDP connection to server");
1487  else if (lossy_socket == clt_udp_sock)
1488  return clt_udp_sock;
1489  return NULL;
1490 }
1491 
1493 {
1494  if (Network) {
1495  for (unsigned int i = 0; i < _Universe->numPlayers(); ++i)
1496  Network[i].logout( false );
1497  delete[] Network;
1498  Network = NULL;
1499  }
1500 }
1501 
1502 void NetClient::Reconnect( std::string srvipadr, unsigned short port )
1503 {
1504  vector< string > usernames;
1505  vector< string > passwords;
1506  vector< SOCKETALT* >udp;
1507  unsigned int i;
1508  if (!Network)
1510  for (i = 0; i < _Universe->numPlayers(); ++i) {
1511  usernames.push_back( Network[i].callsign );
1512  passwords.push_back( Network[i].password );
1513  SOCKETALT *udpsocket = Network[i].logout( true );
1514  if (udpsocket)
1515  udp.push_back( udpsocket );
1516  else
1517  udp.push_back( NULL );
1518  Network[i].disconnect();
1519  }
1521  localSerials.resize( 0 );
1522  for (i = 0; i < _Universe->numPlayers(); ++i)
1523  Network[i].Reinitialize();
1525  //necessary? usually we would ask acctserver for it .. or pass it in NetClient::getConfigServerAddress(srvipadr, port);
1526  for (unsigned int k = 0; k < _Universe->numPlayers(); ++k) {
1527  string err;
1528  if ( !srvipadr.empty() )
1529  Network[k].SetCurrentServerAddress( srvipadr, port );
1530  else
1531  Network[k].SetConfigServerAddress( srvipadr, port );
1532  int response = Network[k].connectLoad( usernames[k], passwords[k], err );
1533  if (response == 0) {
1534  COUT<<"Network login error: \n"<<err<<endl;
1535  UniverseUtil::startMenuInterface( false, "Jumping to system, but got a login error: \n\n"+err );
1536  return;
1537  }
1538  vector< string > *loginResp = Network[k].loginSavedGame( 0 );
1539  if (!loginResp) {
1540  COUT<<"Failed to get a ship";
1541  UniverseUtil::startMenuInterface( false, "Jumping to system, but failed to get a ship!" );
1542  return;
1543  }
1544  cout<<" logged in !"<<endl;
1545  Network[k].Respawn( Network[k].serial );
1546  Network[k].synchronizeTime( udp[k] );
1548  Network[k].inGame();
1549  }
1551 }
1552 
1553 ClientPtr NetClient::ClientsMap::insert( int x, Client *c )
1554 {
1555  if (c != NULL) {
1556  ClientPtr cp( c );
1557  _map.insert( ClientPair( x, cp ) );
1558  return cp;
1559  } else {
1560  return ClientPtr();
1561  }
1562 }
1563 
1564 ClientPtr NetClient::ClientsMap::get( int x )
1565 {
1566  ClientIt it = _map.find( x );
1567  if ( it == _map.end() ) return ClientPtr();
1568  return it->second;
1569 }
1570 
1571 bool NetClient::ClientsMap::remove( int x )
1572 {
1573  size_t s = _map.erase( x );
1574  if (s == 0) return false;
1575  return true;
1576  //shared_ptr takes care of delete
1577 }
1578 
1580 {
1581  if (!un) return Transformation();
1582 //return un->curr_physical_state;
1583 //NETFIXME: Interpolation is kind of borked...?
1584  ClientPtr clt = Clients.get( un->GetSerial() );
1585  Transformation trans;
1586  if (clt) {
1587  clt->elapsed_since_packet += addtime;
1588  trans = clt->prediction->Interpolate( un, clt->elapsed_since_packet );
1589 //cerr << " *** interpolate "<<un->getFullname()<<","<<un->GetSerial()<<" (" << trans.position.i << ", " << trans.position.j << ", " << trans.position.k << ")"<<endl;
1590 //cerr << " *** INTERPOLATE (" << un->curr_physical_state.position.i << ", " << un->curr_physical_state.position.j << ", " << un->curr_physical_state.position.k << "): next deltatime=" << clt->getNextDeltatime() << ", deltatime=" << clt->getDeltatime() << ", this-deltatime=" << this->deltatime << ", elapsed since packet=" << clt->elapsed_since_packet << "\n => (" << trans.position.i << ", " << trans.position.j << ", " << trans.position.k << ") Vel = (" << un->Velocity.i << ", " << un->Velocity.j << ", " << un->Velocity.k << ")" << std::endl;
1591  } else {
1592  trans = un->curr_physical_state;
1593  }
1594  return trans;
1595 }
1596