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
netserver_clients.cpp
Go to the documentation of this file.
1 #include "networking/netserver.h"
2 #include "networking/zonemgr.h"
5 #include "universe_util.h"
6 #include "universe_generic.h"
7 #include "cmd/unit_factory.h"
11 #include "lin_time.h"
12 #include "vs_random.h"
13 #include "save_util.h"
14 
15 extern StarSystem * GetLoadedStarSystem( const char *system );
16 
17 /*
18  *************************************************************
19  **** Adds a new client ***
20  *************************************************************
21  */
22 
23 ClientPtr NetServer::addNewClient( SOCKETALT &sock )
24 {
25  ClientPtr newclt( new Client( sock ) );
26  //New client -> now registering it in thx active client list "Clients"
27  //Store the associated socket
28 
29  allClients.push_back( newclt );
30 
31  COUT<<" - Actual number of clients : "<<allClients.size()<<endl;
32 
33  return newclt;
34 }
35 
36 //zonemgr.cpp
37 extern void displayUnitInfo( Unit *un, const string callsign, const char *type );
38 
39 void NetServer::broadcastUnit( Unit *un, unsigned short zone )
40 {
41  newUnits.push_back( un );
42 }
43 
45 {
46  unsigned short vers[4] = {0, 4951, 4952, 65535};
47  for (ZoneMap::const_iterator zoneiter = zonemgr->zones.begin();
48  zoneiter != zonemgr->zones.end(); ++zoneiter) {
49  unsigned short zone = (*zoneiter).first;
50  for (int verind = 0; verind < 4; verind += 2) {
51  unsigned short minver = vers[verind], maxver = vers[verind+1];
52  NetBuffer netbuf;
53  if (maxver != 65535) netbuf.setVersion( maxver );
54  bool added = false;
55  for (std::vector< UnitContainer >::iterator iter = newUnits.begin();
56  iter != newUnits.end();
57  ++iter) {
58  Unit *un = (*iter).GetUnit();
59  if (un) {
60  StarSystem *sys = un->getStarSystem();
61  if (sys) {
62  unsigned short unzone = sys->GetZone();
63  if (unzone == zone) {
64  added = true;
65  UnitFactory::addBuffer( netbuf, un, true );
66  if (verind == 0)
67  displayUnitInfo( un, string(),
68  ( " * CREATED "+un->getStarSystem()->getFileName() ).c_str() );
69  }
70  }
71  } else {
72  COUT<<"New Unit already killed before being sent!!!"<<endl;
73  }
74  }
75  if (added) {
76  UnitFactory::endBuffer( netbuf );
77  Packet p2;
78  p2.bc_create( CMD_ENTERCLIENT, 0, netbuf.getData(), netbuf.getDataLength(),
79  SENDRELIABLE, __FILE__, PSEUDO__LINE__( 66 ) );
80  zonemgr->broadcast( zone, 0, &p2, true, minver, maxver );
82  }
83  }
84  }
85  newUnits.clear();
86 }
87 
88 /*
89  *************************************************************
90  **** Add a client in the game ***
91  *************************************************************
92  */
93 
94 //**** Make sure to use Lock around system creation in ZoneMgr. ****
95 
96 void NetServer::addClient( ClientPtr clt )
97 {
98  Unit *un = clt->game_unit.GetUnit();
99  if (!un) {
100  COUT<<"Error: adding NULL (dead) client! "<<clt->callsign<<endl;
101  return;
102  }
103  COUT<<">>> SEND ENTERCLIENT =( serial #"<<un->GetSerial()<<" )= --------------------------------------"<<endl;
104  Packet packet2, packet3;
105  string savestr, xmlstr;
106  NetBuffer netbuf;
107  StarSystem *sts;
108  StarSystem *st2;
109 
110  QVector nullVec( 0, 0, 0 );
111  int player = _Universe->whichPlayerStarship( un );
112  if (player == -1)
113  return;
114  cerr<<"ADDING Player number "<<player<<endl;
115  Cockpit *cp = _Universe->AccessCockpit( player );
116  unsigned int oldcp = _Universe->CurrentCockpit();
118  string starsys = cp->savegame->GetStarSystem();
119 
120  unsigned short zoneid;
121  //If we return an existing starsystem we broadcast our info to others
122  sts = zonemgr->addClient( clt, starsys, zoneid );
123 
124  //st2 = _Universe->getStarSystem( starsys);
125  string sysfile = starsys+".system";
126  st2 = GetLoadedStarSystem( sysfile.c_str() );
127  if (!st2) {
128  cerr<<"!!! FATAL ERROR : star system '"<<starsys<<"' not found"<<endl;
129  st2 = _Universe->GenerateStarSystem( sysfile.c_str(), "", Vector( 0, 0, 0 ) );
130  }
131  //On server side this is not done in Cockpit::SetParent()
132  cp->activeStarSystem = st2;
133  un->activeStarSystem = st2;
135  //Cannot use sts pointer since it may be NULL if the system was just created
136  //Try to see if the player is docked on start
137 
138  bool besafe = true;
139  QVector safevec;
140  Unit *dockedUnit = NULL;
141  if (getSaveStringLength( player, "jump_from" ) > 0) {
142  std::string srcsys = getSaveString( player, "jump_from", 0 );
143  Unit *grav;
144  for (un_iter ui = st2->gravitationalUnits().createIterator();
145  (grav = *ui) != NULL;
146  ++ui) {
147  size_t siz = grav->GetDestinations().size();
148  for (unsigned int i = 0; i < siz; ++i)
149  if (srcsys == grav->GetDestinations()[i]) {
151  +QVector( vsrandom.uniformExc( -un->rSize(), un->rSize() ),
152  vsrandom.uniformExc( -un->rSize(),
153  un->rSize() ),
154  vsrandom.uniformExc( -un->rSize(),
155  un->rSize() )
156  ) );
157  besafe = grav->isUnit() != PLANETPTR;
158  }
159  }
160  eraseSaveString( player, "jump_from", 0 );
161  } else {
162  //un->curr_physical_state.position = cp->savegame->GetPlayerLocation();
163  dockedUnit = DockToSavedBases( player, safevec );
164  }
165  if (!dockedUnit) {
166  //safevec == nullVec)
167  if (besafe)
169  else
170  safevec = cp->savegame->GetPlayerLocation();
171  cerr<<"PLAYER NOT DOCKED - STARTING AT POSITION : x="<<safevec.i<<",y="<<safevec.j<<",z="<<safevec.k<<endl;
172  clt->ingame = true;
173  } else {
174  cerr<<"PLAYER DOCKED TO "<<dockedUnit->getFullname()<<" - STARTING DOCKED AT POSITION : x="<<safevec.i<<",y="
175  <<safevec.j<<",z="<<safevec.k<<endl;
176  }
177  clt->loginstate = Client::INGAME;
178  //COUT<<"\tposition : x="<<safevec.i<<" y="<<safevec.j<<" z="<<safevec.k<<endl;
179  cp->savegame->SetPlayerLocation( safevec );
180  un->SetPosAndCumPos( safevec );
181 
182  cp->credits = ( cp->savegame->GetSavedCredits() );
183 
184  //UPDATE THE CLIENT Unit's state
185  un->SetPosition( safevec );
186  if (sts) {
187  //DO NOT DO THAT HERE ANYMORE (VERY BLOCKING ON SERVER SIDE) -> CLIENT ASKS FOR THE NEW SYSTEM UNITS
188  //AND DOWNLOADS INFO
189  //Send info about other ships in the system to "clt"
190  //zonemgr->sendZoneClients( clt);
191 
192  //Send savebuffers and name
193 
194  //Don't need to send ZoneMgr::AddClient
195  //Uses packet's serial number
196  netbuf.addChar( ZoneMgr::AddClient );
197  netbuf.addSerial( un->GetSerial() );
198 
199  netbuf.addString( clt->callsign );
200  SaveNetUtil::GetSaveStrings( clt, savestr, xmlstr, false );
201  netbuf.addString( savestr );
202  netbuf.addString( xmlstr );
204 
205  netbuf.addChar( ZoneMgr::End );
206  //Put the save buffer after the ClientState
207  packet2.bc_create( CMD_ENTERCLIENT, un->GetSerial(),
208  netbuf.getData(), netbuf.getDataLength(),
209  SENDRELIABLE,
210  __FILE__, PSEUDO__LINE__( 1311 ) );
211  COUT<<"<<< SEND ENTERCLIENT("<<un->GetSerial()
212  <<") TO OTHER CLIENT IN THE ZONE------------------------------------------"<<endl;
213  zonemgr->broadcast( clt, &packet2, true );
214  COUT<<"Serial : "<<un->GetSerial()<<endl;
215  }
216  //In all case set the zone and send the client the zone which it is in
217  COUT<<">>> SEND ADDED YOU =( serial #"<<un->GetSerial()<<" )= --------------------------------------"<<endl;
218  un->activeStarSystem->SetZone( zoneid );
219  Packet pp;
220  netbuf.Reset();
221  netbuf.setVersion( clt->netversion );
222  //netbuf.addShort( zoneid);
223  //netbuf.addString( _Universe->current_stardate.GetFullTrekDate());
224  un->BackupState();
225  clt->setLatestTimestamp( packet.getTimestamp() );
226  clt->last_packet = un->old_state;
227  clt->prediction->InitInterpolation( un, un->old_state, 0, clt->getNextDeltatime() );
228  //Add initial position to make sure the client is starting from where we tell him
230  pp.send( CMD_ADDEDYOU, un->GetSerial(), netbuf.getData(),
231  netbuf.getDataLength(), SENDRELIABLE, &clt->cltadr, clt->tcp_sock, __FILE__, PSEUDO__LINE__( 170 ) );
232  netbuf.Reset();
233  zonemgr->getZoneBuffer( un->activeStarSystem->GetZone(), netbuf );
234  packet3.send( CMD_ENTERCLIENT, 0, netbuf.getData(),
235  netbuf.getDataLength(), SENDRELIABLE, &clt->cltadr, clt->tcp_sock, __FILE__, PSEUDO__LINE__( 174 ) );
236 
237  Packet p2;
238  netbuf.Reset();
239  addUnitCargoSnapshot( un, netbuf );
240  netbuf.addSerial( 0 );
241  p2.bc_create( CMD_SNAPCARGO, 0, netbuf.getData(), netbuf.getDataLength(),
242  SENDRELIABLE, __FILE__, PSEUDO__LINE__( 179 ) );
243  zonemgr->broadcast( un->activeStarSystem->GetZone(), un->GetSerial(), &p2, true );
244 
245  COUT<<"ADDED client n "<<un->GetSerial()<<" in ZONE "<<un->activeStarSystem->GetZone()<<" at STARDATE "
247  sendCredits( un->GetSerial(), cp->credits );
248  sendCargoSnapshot( un->GetSerial(), st2->getUnitList() );
249 
250  cp->savegame->LoadSavedMissions(); //loads stuff in active_missions.
251  if (dockedUnit) {
252  int dockport = -1;
253  for (unsigned int i = 0; i < dockedUnit->pImage->dockedunits.size(); ++i) {
254  Unit *tempun;
255  if ( ( tempun = dockedUnit->pImage->dockedunits[i]->uc.GetUnit() ) != NULL )
256  if (tempun == un)
257  dockport = i;
258  }
259  if (dockport >= 0)
260  this->sendDockAuthorize( un->GetSerial(), dockedUnit->GetSerial(), dockport, un->activeStarSystem->GetZone() );
261  }
263 
265  _Universe->SetActiveCockpit( oldcp );
266 
267  //delete cltsbuf;
268  //COUT<<"<<< SENT ADDED YOU -----------------------------------------------------------------------"<<endl;
269 }
270 
271 void NetServer::serverTimeInitUDP( ClientPtr clt, NetBuffer &netbuf )
272 {
273  Packet p2;
274  NetBuffer timeBuf;
275  //If client sent an unsigned short.
276  if (netbuf.getSize() > 1) {
277  unsigned short clt_port = netbuf.getShort();
278  if (clt_port) {
279  AddressIP adr( clt->cltadr, clt_port );
280  clt->setUDP( udpNetwork, adr );
281  } else {
282  clt->setTCP();
283  }
284  }
285  timeBuf.addDouble( queryTime() ); //get most "up-to-date" time.
286  //NETFIXME: is SENDANDFORGET really UDP? No. Use the client's lossy_socket.
287  p2.send( CMD_SERVERTIME, 0, timeBuf.getData(),
288  timeBuf.getDataLength(), SENDANDFORGET, &clt->cltudpadr, *clt->lossy_socket, __FILE__, PSEUDO__LINE__( 691 ) );
289 }
290 
291 /*
292  **************************************************************
293  **** Removes a client and notify other clients
294  **************************************************************
295  */
296 
297 void NetServer::removeClient( ClientPtr clt )
298 {
299  Packet packet2;
300  Unit *un = clt->game_unit.GetUnit();
301  if (!un)
302  return; //Don't broadcast if already dead.
303 
304  clt->ingame = false;
305  //Remove the client from its current starsystem
306  zonemgr->removeClient( clt );
307  //Broadcast to other players
308  packet2.bc_create( CMD_EXITCLIENT, un->GetSerial(),
309  NULL, 0, SENDRELIABLE,
310  __FILE__, PSEUDO__LINE__( 1311 ) );
311  zonemgr->broadcast( clt, &packet2, true );
312 }
313 
314 Quaternion MinRotationFromDirections( Vector start, Vector finish, double &theta /*just for kicks*/ )
315 {
316  Vector rotation = finish.Cross( start );
317  double mag = rotation.Cast().Magnitude();
318  if (mag >= 1)
319  mag = 1;
320  if (mag < 1e-6) {
321  theta = 0;
322  return identity_quaternion;
323  }
324  theta = asin( mag );
325  if (start.Dot( finish ) < 0) theta += M_PI/2;
326  float s = (float) cos( theta*.5 );
327  rotation = rotation.Scale( 1./mag );
328  return Quaternion( s, rotation*sin( theta*.5 ) );
329 }
330 
332 {
333  Matrix tmp;
334  quat.to_matrix( tmp );
335  return TransformNormal( tmp, input );
336 }
337 
338 /*
339  **************************************************************
340  **** Adds the client update to current client's zone snapshot
341  **************************************************************
342  */
344  ClientState ocs /*old*/,
345  QVector realtargetpos,
346  Vector realtargetvel,
347  Vector targetpos,
348  Vector targetvel )
349 {
350  float t = 0;
351  static bool debug_predict = XMLSupport::parse_bool( vs_config->getVariable( "network", "debug_prediction", "false" ) );
352  double velaimtheta = 0;
353  double orientaimtheta = 0;
354  Matrix trans;
355  ClientState OrientationAim( cs );
356  ClientState VelocityAim( cs );
357  bool VelocityAimValid = false;
358  bool OrientationAimValid = false;
359  cs.getOrientation().to_matrix( trans );
360  Vector dir = trans.getR();
361  targetvel = targetvel-cs.getVelocity();
362  realtargetvel = realtargetvel-cs.getVelocity();
363  Vector targetperp = targetpos.Cross( targetvel );
364  realtargetpos = ( realtargetpos-cs.getPosition() );
365  Vector realtargetperp = realtargetpos.Cast().Cross( realtargetvel );
366  Vector targetdir = targetpos;
367  targetdir.Normalize();
368  float targetperpmag = targetperp.Magnitude();
369  float realtargetperpmag = realtargetperp.Magnitude();
370  static float cos_min_angle =
371  cos( M_PI*(1./180)*XMLSupport::parse_float( vs_config->getVariable( "network", "max_lead_prediction_angle", "60" ) ) ); //120 degree leeway for using this method
372  if (targetperpmag > .001 && realtargetperpmag > .001 && targetvel.MagnitudeSquared() > .25
373  && realtargetvel.MagnitudeSquared() > .25 && dir.Dot( targetdir ) >= cos_min_angle) {
374  //gotta make sure target is at least in viewscreen before giving benefit of the doubt lead
375  targetperp = targetperp*(1./targetperpmag);
376  realtargetperp = realtargetperp*(1./realtargetperpmag); //compute a unit direction perpendicular to the plane made by the target and its relative velocity (to playerstarship)... we'll use this to see how far off that plane the velocity actually is
377  float distoffplane = targetperp.Dot( dir );
378  Vector dirperp = targetperp.Scale( distoffplane );
379  Vector dirplane = dir-dirperp; //this is the projection of the player's orientation direction onto the plane if the target and its velocity... if he were aligned with the arc of travel of the target he would Dot(targetperp,dir) would be zero and this wouldn't change the dir
380  //now we have to figure out how far out the intersection point of dirplane and targetvel are...
381  //solve for t and k reltargetpos+targetvel*t=k*dirplane
382  float posx = targetpos.i;
383  float posy = targetpos.j;
384  float dirx = dirplane.i;
385  float diry = dirplane.j;
386  float velx = targetvel.i;
387  float vely = targetvel.j;
388  if ( fabs( dirplane.i ) <= fabs( dirplane.j ) && fabs( dirplane.i ) <= fabs( dirplane.k ) ) {
389  posx = targetpos.k;
390  posy = targetpos.j;
391  dirx = dirplane.k;
392  diry = dirplane.j;
393  velx = targetvel.k;
394  vely = targetvel.j;
395  }
396  if ( fabs( dirplane.j ) <= fabs( dirplane.i ) && fabs( dirplane.j ) <= fabs( dirplane.k ) ) {
397  posx = targetpos.i;
398  posy = targetpos.k;
399  dirx = dirplane.i;
400  diry = dirplane.k;
401  velx = targetvel.i;
402  vely = targetvel.k;
403  }
404  if ( fabs( diry ) > fabs( dirx ) ) {
405  float tmp = posx;
406  posx = posy;
407  posy = tmp;
408  tmp = dirx;
409  dirx = diry;
410  diry = tmp;
411  tmp = velx;
412  velx = vely;
413  vely = tmp;
414  }
415  {
416  float num = diry*posx/dirx-posy;
417  float denom = vely-diry*velx/dirx;
418  if (fabs( denom ) < .0001)
419  t = 0;
420  else
421  t = num/denom;
422  //if (t<=0) t=0;
423  }
424  static float velaimlim = XMLSupport::parse_float( vs_config->getVariable( "network", "max_lead_prediction", "10" ) );
425  if (fabs( t ) < velaimlim) {
426  Vector newdirplane = realtargetpos+realtargetvel*t;
427  Vector newdirperp = realtargetperp.Scale( distoffplane );
428  newdirplane.Normalize();
429  newdirplane *= dirplane.Magnitude();
430  Vector newdir = newdirplane+newdirperp;
431  newdir.Normalize();
432  Vector newright, newup;
433  CrossProduct( trans.getQ(), newdir, newright );
434  CrossProduct( newdir, newright, newup );
435  newright.Normalize();
436  newup.Normalize();
437  Quaternion forient = Quaternion::from_vectors( newright, newup, newdir );
438  Vector fvel = ApplyQuaternion( MinRotationFromDirections( dir, newdir, velaimtheta ), cs.getAngularVelocity() );
439  VelocityAimValid = FINITE( fvel.i ) && FINITE( fvel.j ) && FINITE( fvel.k ) && FINITE( forient.s ) && FINITE(
440  forient.v.i ) && FINITE( forient.v.j ) && FINITE( forient.v.k );
441  VelocityAim.setAngularVelocity( fvel );
442  VelocityAim.setOrientation( forient );
443  }
444  }
445  {
446  //some other scheme for when target is still...
447  targetpos.Normalize();
448  realtargetpos.Normalize();
449  Quaternion quat = MinRotationFromDirections( targetpos, realtargetpos, orientaimtheta );
450  Quaternion forient = cs.getOrientation()*quat;
451  Vector fvel = ApplyQuaternion( quat, cs.getAngularVelocity() );
452 
453  OrientationAimValid = FINITE( fvel.i ) && FINITE( fvel.j ) && FINITE( fvel.k ) && FINITE( forient.s ) && FINITE(
454  forient.v.i ) && FINITE( forient.v.j ) && FINITE( forient.v.k );
455  OrientationAim.setOrientation( forient );
456  OrientationAim.setAngularVelocity( fvel );
457  }
458  if (VelocityAimValid) {
459  if (debug_predict)
460  printf( "Velocity aim lead %f, rot %f deg\n", t, velaimtheta*180/M_PI );
461  return VelocityAim;
462  }
463  if (OrientationAimValid) {
464  if (debug_predict)
465  printf( "Using orientation aim rot %f deg\n", orientaimtheta*180/M_PI );
466  return OrientationAim;
467  }
468  fprintf( stderr, "Got non-finite result for aim_assist (client sent bad info?)\n" );
469  return cs;
470 }
471 
472 ClientState aim_assist( ClientState cs, ClientState ocs /*old*/, Unit *target, Vector targetpos, Vector targetvel )
473 {
474  return aim_assist( cs, ocs, target->Position(), target->Velocity, targetpos, targetvel );
475 }
476 
478  float y,
479  float z,
480  float vx,
481  float vy,
482  float vz,
483  float rx,
484  float ry,
485  float rz,
486  float vrx,
487  float vry,
488  float vrz,
489  float forex,
490  float forey,
491  float forez )
492 {
493  Vector fore( forex, forey, forez );
494  fore.Normalize();
495  Vector up( 0, 1, 0 );
496  if (fore.j > .9)
497  up = Vector( 0, 0, 1 );
498  Vector right;
499  CrossProduct( up, fore, right );
500  CrossProduct( fore, right, up );
501  right.Normalize();
502  up.Normalize();
503  fore.Normalize();
504  ClientState tmp( 1, QVector( 0, 0, 0 ), Quaternion::from_vectors( right, up, fore ), Vector( 0, 0, 0 ), Vector( 0,
505  0,
506  0 ), Vector(
507  0,
508  1,
509  0 ) );
510  tmp = aim_assist( tmp, tmp, QVector( rx, ry, rz ), Vector( vrx, vry, vrz ), Vector( x, y, z ), Vector( vx, vy, vz ) );
511  Matrix mat;
512  tmp.getOrientation().to_matrix( mat );
513  printf( "Final Direction %.3f %.3f %.3f (Up %.2f %.2f %.2f)\n", mat.getR().i, mat.getR().j, mat.getR().k,
514  mat.getQ().i, mat.getQ().j, mat.getQ().k );
515  return tmp;
516 }
517 
518 void NetServer::posUpdate( ClientPtr clt )
519 {
520 //NETFIXME: do a sanity check on the position.
521 
522  NetBuffer netbuf( packet.getData(), packet.getDataLength() );
523  Unit *un = clt->game_unit.GetUnit();
524  if (!un)
525  return; //Don't receive data if dead.
526 
527  ObjSerial clt_serial = netbuf.getSerial();
528  //clt->setLatestTimestamp(packet.getTimestamp( ));
529  clt->setLatestTimestamp( packet.getTimestamp() );
530  clt->elapsed_since_packet = 0;
531  if ( clt_serial != un->GetSerial() )
532  cerr<<"!!! ERROR : Received an update from a serial that differs with the client we found !!!"<<endl;
533  //VSExit(1);
534  ClientState cs2;
535  //Set old position
536  un->BackupState();
537  //Update client position in client list : should be enough like it is below
538  cs2 = netbuf.getClientState();
539  ClientState cs( cs2 );
540  bool inSpec = 0;
541  if (clt->netversion > 4960)
542  inSpec = netbuf.getChar() ? 1 : 0;
543  if ( !FINITE( cs.getPosition().i ) || !FINITE( cs.getPosition().j ) || !FINITE( cs.getPosition().k ) ) {
544  cerr<<"Unit "<<clt_serial<<" sent me an invalid position"<<endl;
545  cs = un->old_state;
546  sendForcePosition( clt );
547  }
548  static bool do_aim_assist = XMLSupport::parse_bool( vs_config->getVariable( "network", "aim_assist", "true" ) );
549  if (do_aim_assist && netbuf.getSize() > netbuf.getOffset()+2) {
550  ObjSerial target_serial = netbuf.getSerial();
551  if (target_serial != 0) {
552  unsigned int zone = un->getStarSystem()->GetZone();
553  Unit *target = zonemgr->getUnit( target_serial, zone );
554  Vector rel_target_position = netbuf.getVector();
555  QVector target_position = cs.getPosition()+rel_target_position;
556  Vector target_velocity = netbuf.getVector();
557  if ( !FINITE( target_position.i ) || !FINITE( target_position.j ) || !FINITE( target_position.k ) ) {
558  cerr<<"Unit "<<clt_serial<<" sent me an invalid target position for aim assist, targ="<<target_serial<<endl;
559  if (target) {
560  NetBuffer netbuf;
561  clt->versionBuf( netbuf );
562  netbuf.addFloat( clt->getDeltatime() );
563  ClientState cst( target );
564 
565  //copied and pasted from zonemgr.cpp:addPosition
566  netbuf.addChar( ZoneMgr::FullUpdate );
567  netbuf.addShort( target->GetSerial() );
568  netbuf.addClientState( cst );
569  netbuf.addFloat( target->energy );
570 
571  Packet pckt;
572  pckt.send( CMD_SNAPSHOT, 1,
573  netbuf.getData(), netbuf.getDataLength(),
574  SENDRELIABLE, &(clt->cltadr), clt->tcp_sock,
575  __FILE__, PSEUDO__LINE__( 547 ) );
576  }
577  } else if (target) {
578  cs = aim_assist( cs, clt->last_packet, target, rel_target_position, target_velocity );
579  }
580  }
581  }
582  static bool debugPos = XMLSupport::parse_bool( vs_config->getVariable( "network", "debug_position_interpolation", "false" ) );
583  if (debugPos) COUT<<"Received ZoneMgr::PosUpdate from client "<<clt_serial<<" *** cs="<<cs<<endl;
584  un->curr_physical_state.position = cs.getPosition();
585  un->curr_physical_state.orientation = cs.getOrientation();
586  un->Velocity = cs.getVelocity();
587  un->AngularVelocity = cs.getAngularVelocity();
588 
589  un->graphicOptions.WarpRamping = (inSpec != un->graphicOptions.InWarp);
590  un->graphicOptions.InWarp = inSpec;
591 
592  assert( clt->prediction );
593  clt->prediction->InitInterpolation( un, clt->last_packet, clt->getDeltatime(), clt->getNextDeltatime() );
594  //un->curr_physical_state.position = clt->prediction->InterpolatePosition( un, 0);
595  clt->last_packet = cs;
596  //deltatime has already been updated when the packet was received
597  Cockpit *cp = _Universe->isPlayerStarship( un );
598  if (cp)
599  cp->savegame->SetPlayerLocation( un->curr_physical_state.position );
600  else if (debugPos)
601  COUT<<"ERROR: Client has NULL cockpit. Does he have two clients ingame? ser="<<un->GetSerial()<<", callsign="
602  <<clt->callsign<<endl;
603  snapchanged = 1;
604 }
605 
606 /*
607  *************************************************************
608  **** Disconnect a client ***
609  *************************************************************
610  */
611 void AddWriteSave( std::string &netbuf, int cpnum )
612 {
613  string savestr, xmlstr;
614  SaveNetUtil::GetSaveStrings( cpnum, savestr, xmlstr, true );
615  addSimpleString( netbuf, savestr );
616  addSimpleString( netbuf, xmlstr );
617 }
618 
619 void AcctLogout( VsnetHTTPSocket *acct_sock, ClientPtr clt )
620 {
621  if (acct_sock == NULL) return;
622  if (clt) {
623  std::string netbuf;
624 
625  Unit *un = clt->game_unit.GetUnit();
626  int cpnum = _Universe->whichPlayerStarship( un );
627  bool dosave = false;
628  if (clt->loginstate < Client::INGAME)
629  dosave = false;
630  addSimpleChar( netbuf, dosave ? ACCT_SAVE_LOGOUT : ACCT_LOGOUT );
631  addSimpleString( netbuf, clt->callsign );
632  addSimpleString( netbuf, clt->passwd );
633  if (dosave)
634  AddWriteSave( netbuf, cpnum );
635  if ( !acct_sock->sendstr( netbuf ) )
636  COUT<<"ERROR sending LOGOUT to account server"<<endl;
637  }
638 }
639 
640 void NetServer::disconnect( ClientPtr clt, const char *debug_from_file, int debug_from_line )
641 {
642  COUT<<"enter "<<__PRETTY_FUNCTION__<<endl
643  <<" *** from "<<debug_from_file<<":"<<debug_from_line<<endl
644  <<" *** disconnecting "<<clt->callsign<<" because of "
645  <<clt->_disconnectReason<<endl;
646 
647  logout( clt );
648 }
649 
650 /*** Same as disconnect but do not respond to client since we assume clean exit ***/
651 void NetServer::logout( ClientPtr clt )
652 {
653  Packet p, p1, p2;
654  std::string netbuf;
655  Unit *un = clt->game_unit.GetUnit();
656  std::string callsign = clt->callsign;
657  if (clt->loginstate == Client::WAITLISTED) {
658  std::map< std::string, WaitListEntry >::iterator iter = waitList.find( clt->callsign );
659  if (waitList.end() != iter)
660  waitList.erase( iter );
661  clt->loginstate = Client::CONNECTED;
662  }
663  if (acctserver && clt->loginstate >= Client::LOGGEDIN && !clt->jumpok)
664  AcctLogout( acct_sock, clt );
665  clt->tcp_sock.disconnect( __PRETTY_FUNCTION__ );
666  COUT<<"Client "<<clt->callsign<<" disconnected"<<endl;
667  COUT<<"There were "<<allClients.size()<<" clients - ";
668  allClients.remove( clt );
669  //Removes the client from its starsystem
670  this->removeClient( clt );
671  //Say true as 2nd arg because we don't want the server to broadcast since player is leaving hte game
672  if (un)
673  un->Kill( true, true );
674  if (clt->loginstate >= Client::LOGGEDIN) {
675  for (unsigned int i = 0; i < _Universe->numPlayers(); i++) {
676  Cockpit *cp = _Universe->AccessCockpit( i );
677  if (cp->savegame && cp->savegame->GetCallsign() == callsign) {
678  cp->savegame->SetCallsign( "" );
679  unused_players.push( i );
680  }
681  }
682  }
683  clt.reset();
684  COUT<<allClients.size()<<" clients left"<<endl;
685  nbclients--;
686 }
687