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
zonemgr.cpp
Go to the documentation of this file.
3 #include "universe_generic.h"
4 #include "universe_util.h"
5 #include "star_system_generic.h"
6 #include "cmd/unit_generic.h"
7 #include "cmd/unit_factory.h"
8 #include "gfx/cockpit_generic.h"
11 #include "networking/zonemgr.h"
12 #include "vs_globals.h"
13 #include "endianness.h"
14 #include <assert.h>
15 #include "networking/netserver.h"
16 #include "vs_random.h"
17 
18 extern StarSystem * GetLoadedStarSystem( const char *system );
19 
20 unsigned short ZoneInfo::next_zonenum = 0;
21 
23 {}
24 
25 /*
26  ***********************************************************************************************
27  **** addZone ****
28  ***********************************************************************************************
29  */
30 
31 void ZoneMgr::addSystem( string &sysname, string &system )
32 {
33  Systems.insert( sysname, system );
34 }
35 
36 string ZoneMgr::getSystem( string &name )
37 {
38  return Systems.get( name );
39 }
40 /*
41  ***********************************************************************************************
42  **** getZoneBuffer : returns a buffer containing zone info ****
43  ***********************************************************************************************
44  */
45 
46 void displayUnitInfo( Unit *un, const string callsign, const char *type )
47 {
48  cout<<type;
49  if (!un) {
50  cout<<"\'"<<callsign<<"\' (dead)"<<endl;
51  } else {
52  {
53  char tmp[10];
54  sprintf( tmp, "% 5d ", un->GetSerial() );
55  cout<<tmp;
56  }
57  cout<<UnitUtil::getFactionName( un )<<" "<<un->getFullname()<<" ("<<un->name<<")";
58  Flightgroup *fg = un->getFlightgroup();
59  if (fg) cout<<", \'"<<fg->name<<"\' "<<un->getFgSubnumber();
60  if ( !callsign.empty() && (!fg || callsign != fg->name) )
61  cout<<", callsign \'"<<callsign<<"\'";
62  cout<<endl;
63  }
64 }
65 
66 //Send one by one a CMD_ADDLCIENT to the client for every ship in the star system we enter
67 void ZoneMgr::getZoneBuffer( unsigned short zoneid, NetBuffer &netbuf )
68 {
69  LI k;
70  int nbclients = 0;
71  Packet packet2;
72  string savestr, xmlstr;
73 
74  //Loop through client in the same zone to send their current_state and save and xml to "clt"
75  std::set< ObjSerial >activeObjects;
76  ZoneInfo *zi = GetZoneInfo( zoneid );
77  if (zi == NULL) {
78  COUT<<"\t>>> WARNING: Did not send info about "<<nbclients<<" other ships because of empty (inconsistent?) zone"<<endl;
79  } else {
80  ClientList *lst = &zi->zone_list;
81  for (k = lst->begin(); k != lst->end(); k++) {
82  ClientPtr kp( *k );
83  //Test if *k is the same as clt in which case we don't need to send info
84  if (true) {
85  //kp->ingame)
86  Unit *un = kp->game_unit.GetUnit();
87  if (un->hull < 0 || !un)
88  continue;
89  assert( un->GetSerial() != 0 );
90  SaveNetUtil::GetSaveStrings( kp, savestr, xmlstr, false );
91  //Add the ClientState at the beginning of the buffer -> NO THIS IS IN THE SAVE !!
92  //netbuf.addClientState( ClientState( kp->game_unit.GetUnit()));
93  //Add the callsign and save and xml strings
94  netbuf.addChar( ZoneMgr::AddClient );
95  netbuf.addSerial( un->GetSerial() );
96  netbuf.addString( kp->callsign );
97  netbuf.addString( savestr );
98  netbuf.addString( xmlstr );
99  netbuf.addTransformation( kp->game_unit.GetUnit()->curr_physical_state );
100  activeObjects.insert( un->GetSerial() );
101  nbclients++;
102  }
103  }
104  {
105  Unit *un;
106  for (un_iter ui = zi->star_system->getUnitList().createIterator();
107  (un = *ui) != NULL;
108  ++ui) {
109  //NETFIXME Asteroids are disabled for now!
110  if (un->hull < 0 || un->isUnit() == ASTEROIDPTR) //no point sending a zombie.
111  continue;
112  ObjSerial ser = un->GetSerial();
113  assert( ser != 0 );
114  if ( activeObjects.find( ser ) == activeObjects.end() ) {
115  UnitFactory::addBuffer( netbuf, un, false );
116  activeObjects.insert( un->GetSerial() );
117  nbclients++;
118  }
119  }
120  netbuf.addChar( ZoneMgr::End );
121  }
122  COUT<<"\t>>> GOT INFO ABOUT "<<nbclients<<" OTHER SHIPS"<<endl;
123  }
124 }
125 
126 StarSystem* ZoneMgr::addZone( string starsys )
127 {
128  StarSystem *sts = NULL;
129  string sysfile = starsys+".system";
130  if ( ( sts = GetLoadedStarSystem( sysfile.c_str() ) ) ) {
131  cerr<<"--== STAR SYSTEM "<<starsys<<" ALREADY EXISTS ==--"<<endl;
132  return sts;
133  }
134  //Add a network zone (StarSystem equivalent) and create the new StarSystem
135  //StarSystem is not loaded so we generate it
136  COUT<<">>> ADDING A NEW ZONE = "<<starsys<<" - ZONE # = "<<_Universe->star_system.size()<<endl;
137  COUT<<"--== STAR SYSTEM NOT FOUND - GENERATING ==--"<<endl;
138  //list<Unit *> ulst;
139  //Generate the StarSystem
140  _Universe->netLock( true );
141  string starsysfile = starsys+".system";
142  //ComputeSystemSerials now done in Universe::Generate1
143  //UniverseUtil::ComputeSystemSerials( starsysfile);
144  //sts = new StarSystem( starsysfile.c_str(), Vector(0,0,0));
145  //_Universe->Generate2( sts);
146  sts = _Universe->GenerateStarSystem( starsysfile.c_str(), "", Vector( 0, 0, 0 ) );
147  bool newSystem = true;
148  unsigned int i;
149  for (i = 0; i < _Universe->star_system.size(); i++)
150  if (_Universe->star_system[i] == sts) {
151  newSystem = false;
152  break;
153  }
154  if (newSystem)
155  printf( "newSystem is somehow true!!!" );
156  /*
157  * while (newSystem||i>=zone_list.size()) {
158  * newSystem=false;
159  * ClientList* lst = new ClientList;
160  * zone_list.push_back( lst);
161  * //zone_unitlist.push_back( ulst);
162  * // Add zero as number of clients in zone since we increment in ZoneMgr::addClient()
163  * zone_clients.push_back( 0);
164  * //zone_units.push_back( 0);
165  * COUT<<"<<< NEW ZONE ADDED - # OF ZONES = "<<_Universe->star_system.size()<<endl;
166  * }
167  */
168  unsigned short zone = ZoneInfo::next_zonenum;
169  zones.insert( ZoneMap::value_type( zone, ZoneInfo( sts ) ) );
170  sts->SetZone( zone );
171  _Universe->netLock( false );
172  return sts;
173 }
174 
175 /*
176  ***********************************************************************************************
177  **** GetZone ****
178  ***********************************************************************************************
179  */
180 
181 //Return the client list that are in the zone # serial
183 {
184  ZoneMap::iterator iter = zones.find( serial );
185  if ( iter == zones.end() )
186  return NULL;
187  else
188  return &( (*iter).second );
189 }
190 
191 //Return the client list that are in the zone # serial
193 {
194  ZoneInfo *zi = GetZoneInfo( serial );
195  if (zi)
196  return &zi->zone_list;
197  else
198  return NULL;
199 }
200 
201 //Adds a client to the zone # serial
202 /*
203  * void ZoneMgr::addClient( ClientWeakPtr clt, int zone)
204  * {
205  * ClientList* lst = zone_list[zone];
206  * if( lst == NULL )
207  * zone_list[zone] = lst = new list<Client*>;
208  *
209  * lst->push_back( clt );
210  * zone_clients[zone]++;
211  * // Now we add the unit in that starsystem
212  * sts->AddUnit( clt->game_unit);
213  * }
214  */
215 
216 /*
217  ***********************************************************************************************
218  **** addUnit ****
219  ***********************************************************************************************
220  */
221 
222 /*
223  * void ZoneMgr::addUnit( Unit * un, int zone)
224  * {
225  * zone_unitlist[zone].push_back( un);
226  * zone_units[zone]++;
227  * }
228  */
229 
230 /*
231  ***********************************************************************************************
232  **** removeUnit ****
233  ***********************************************************************************************
234  */
235 
236 /*
237  * void ZoneMgr::removeUnit( Unit * un, int zone)
238  * {
239  * if( zone_unitlist[zone].empty())
240  * {
241  * cerr<<"Trying to remove unit on an empty list !!"<<endl;
242  * exit( 1);
243  * }
244  * zone_unitlist[zone].remove( un);
245  * zone_units[zone]--;
246  * }
247  */
248 
249 //Returns NULL if no corresponding Unit was found
250 Unit* ZoneMgr::getUnit( ObjSerial unserial, unsigned short zone )
251 {
252  ZoneInfo *zi = GetZoneInfo( zone );
253  if (!zi) return NULL;
254  Unit *un = NULL;
255  //Clients not ingame are removed from the drawList so it is ok not to test that
256  for (un_iter iter = ( zi->getSystem()->getUnitList() ).createIterator(); (un = *iter) != NULL; ++iter)
257  if (un->GetSerial() == unserial)
258  break;
259  return un;
260 }
261 
262 /*
263  ***********************************************************************************************
264  **** addClient ****
265  ***********************************************************************************************
266  */
267 
268 StarSystem* ZoneMgr::addClient( ClientPtr cltw, string starsys, unsigned short &num_zone )
269 {
270  //Remove the client from old starsystem if needed and add it in the new one
271  StarSystem *sts = NULL;
272 
273  sts = this->addZone( starsys );
274 
275  //Get the index of the existing star_system as it represents the zone number
276  num_zone = sts->GetZone();
277 
278  COUT<<">> ADDING CLIENT IN ZONE # "<<num_zone<<endl;
279  //Adds the client in the zone
280 
281  ZoneInfo *zi = GetZoneInfo( num_zone );
282  ClientList *lst = &zi->zone_list;
283 
284  lst->push_back( cltw );
285  ClientPtr clt( cltw );
286  zi->zone_clients++;
287  cerr<<zi->zone_clients<<" clients now in zone "<<num_zone<<endl;
288 
289  //QVector safevec;
290  Unit *addun = clt->game_unit.GetUnit();
291  if (addun) {
292  _Universe->netLock( true );
293  sts->AddUnit( addun );
294  displayUnitInfo( addun, clt->callsign, "ENTERING NEW CLIENT: " );
295  _Universe->netLock( false );
296  } else {
297  cerr<<"dead client attempted to be added to system: refusing\n";
298  }
299  return sts;
300 }
301 
302 /*
303  ***********************************************************************************************
304  **** removeClient ****
305  ***********************************************************************************************
306  */
307 
308 //Remove a client from its zone
310 {
311  StarSystem *sts;
312  Unit *un = clt->game_unit.GetUnit();
313  int zonenum = -1;
314  /*
315  * if (un && un->activeStarSystem)
316  * zonenum = un->activeStarSystem->GetZone();
317  * else {
318  */
319  for (ZoneMap::iterator iter = zones.begin(); iter != zones.end(); ++iter) {
320  bool found = false;
321  ClientList *lst = &( (*iter).second.zone_list );
322  for (ClientList::iterator q = lst->begin(); q != lst->end();) {
323  ClientPtr cwp = *q;
324  ClientPtr ocwp( clt );
325  if ( ( !(cwp < ocwp) ) && !(ocwp < cwp) ) {
326  q = lst->erase( q );
327  zonenum = (*iter).first;
328  found = true;
329  break;
330  } else {
331  ++q;
332  }
333  }
334  if (found)
335  break;
336  }
337  displayUnitInfo( un, clt->callsign, " *** REMOVING client: " );
338  if (zonenum < 0) {
339  cerr<<"Client "<<clt->callsign<<" not found in any zone when attempting to remove it"<<endl;
340  //NETFIXME CRASH
341 
342  return;
343  }
344  ZoneInfo *zi = GetZoneInfo( zonenum );
345  zi->zone_clients--;
346  cerr<<zi->zone_clients<<" clients left in zone "<<zonenum<<endl;
347  if (!un)
348  return;
349  sts = zi->star_system;
350  if (un->GetHull() < 0)
351  un->Kill( true, true );
352  else
353  sts->RemoveUnit( un );
354  clt->ingame = false;
355  if (clt->loginstate > Client::LOGGEDIN)
356  clt->loginstate = Client::LOGGEDIN;
357  //SHIP MAY NOT HAVE BEEN KILLED BUT JUST CHANGED TO ANOTHER STAR SYSTEM -> NO KILL
358  //un->Kill();
359 }
360 
361 /*
362  ***********************************************************************************************
363  **** broadcast : broadcast a packet in a zone ****
364  ***********************************************************************************************
365  */
366 
367 //Broadcast a packet to a client's zone clients
368 void ZoneMgr::broadcast( ClientPtr fromcltw, Packet *pckt, bool isTcp, unsigned short minver, unsigned short maxver )
369 {
370  ClientPtr fromclt( fromcltw );
371  Unit *un = fromclt->game_unit.GetUnit();
372  if ( !un || !un->getStarSystem() ) {
373  cerr<<"Trying to broadcast information with dead client unit"<<pckt->getCommand()<<endl;
374  return;
375  }
376  unsigned short zonenum = un->getStarSystem()->GetZone();
377  ClientList *lst = GetZone( zonenum );
378  if (lst == NULL) {
379  cerr<<"Trying to send update to nonexistant zone "<<zonenum<<pckt->getCommand()<<endl;
380  return;
381  }
382  for (LI i = lst->begin(); i != lst->end(); i++) {
383  ClientPtr clt( *i );
384  Unit *un2 = clt->game_unit.GetUnit();
385  //Broadcast to other clients
386  if ( (isTcp || clt->ingame) && clt->netversion >= minver && clt->netversion <= maxver
387  && ( (un2 == NULL) || ( un->GetSerial() != un2->GetSerial() ) ) ) {
388  COUT<<"BROADCASTING "<<pckt->getCommand()
389  <<" to client #";
390  if (un2)
391  cout<<un2->GetSerial();
392  else
393  cout<<"dead";
394  cout<<endl;
395  if (isTcp)
396  pckt->bc_send( clt->cltadr, clt->tcp_sock );
397  else
398  pckt->bc_send( clt->cltudpadr, *clt->lossy_socket );
399  }
400  }
401 }
402 
403 /*
404  ***********************************************************************************************
405  **** broadcast : broadcast a packet in a zone ****
406  ***********************************************************************************************
407  */
408 
409 //Broadcast a packet to a zone clients with its serial as argument
410 void ZoneMgr::broadcast( int zone, ObjSerial serial, Packet *pckt, bool isTcp, unsigned short minver, unsigned short maxver )
411 {
412  ClientList *lst = GetZone( zone );
413  if (lst == NULL) return;
414  for (LI i = lst->begin(); i != lst->end(); i++) {
415  ClientPtr clt( *i );
416  //Broadcast to all clients including the one who did a request
417  //Allow packets to non-ingame clients to get lost if requested UDP.
418  if ( (isTcp || clt->ingame) && clt->netversion >= minver && clt->netversion <= maxver
419  /*&& un->GetSerial() != un2->GetSerial()*/ ) {
420 //COUT<<endl;
421  if (isTcp)
422  pckt->bc_send( clt->cltadr, clt->tcp_sock );
423  else
424  pckt->bc_send( clt->cltudpadr, *clt->lossy_socket );
425  }
426  }
427 }
428 
429 //Broadcast a packet to a zone clients with its serial as argument but not to the originating client
430 void ZoneMgr::broadcastNoSelf( int zone, ObjSerial serial, Packet *pckt, bool isTcp )
431 {
432  ClientList *lst = GetZone( zone );
433  if (lst == NULL) return;
434  for (LI i = lst->begin(); i != lst->end(); i++) {
435  ClientPtr clt( *i );
436  Unit *broadcastTo = clt->game_unit.GetUnit();
437  //Broadcast to all clients including the one who did a request
438  if ( (isTcp || clt->ingame) && ( (!broadcastTo) || broadcastTo->GetSerial() != serial ) ) {
439  if (isTcp)
440  pckt->bc_send( clt->cltadr, clt->tcp_sock );
441  else
442  pckt->bc_send( clt->cltudpadr, *clt->lossy_socket );
443  }
444  }
445 }
446 
447 /*
448  ***********************************************************************************************
449  **** broadcastSample : broadcast sound sample to players in the zone and on same frequency ****
450  ***********************************************************************************************
451  */
452 
453 //Broadcast a packet to a zone clients with its serial as argument
454 //NETFIXME: Should this be always TCP?
455 void ZoneMgr::broadcastSample( int zone, ObjSerial serial, Packet *pckt, float frequency )
456 {
457  ClientList *lst = GetZone( zone );
458  Unit *un;
459  if (lst == NULL) return;
460  for (LI i = lst->begin(); i != lst->end(); i++) {
461  ClientPtr clt( *i );
462  un = clt->game_unit.GetUnit();
463  //Broadcast to all clients excluding the one who did a request and
464  //excluding those who are listening on a different frequency, those who aren't communicating
465  //and those who don't have PortAudio support
466  if ( clt->ingame && clt->comm_freq != -1 && clt->portaudio && clt->comm_freq == frequency
467  && ( (!un) || (un->GetSerial() != serial) ) )
468  pckt->bc_send( clt->cltadr, clt->tcp_sock );
469  }
470 }
471 
472 /*
473  ***********************************************************************************************
474  **** broadcastText : broadcast a text message to players in the zone and on same frequency ****
475  ***********************************************************************************************
476  */
477 
478 //Broadcast a packet to a zone clients with its serial as argument
479 //Always TCP.
480 void ZoneMgr::broadcastText( int zone, ObjSerial serial, Packet *pckt, float frequency )
481 {
482  ClientList *lst = GetZone( zone );
483  Unit *un;
484  if (lst == NULL) return;
485  for (LI i = lst->begin(); i != lst->end(); i++) {
486  ClientPtr clt( *i );
487  un = clt->game_unit.GetUnit();
488  //Broadcast to all clients excluding the one who did a request and
489  //excluding those who are listening on a different frequency, those who aren't communicating
490  //and those who don't have PortAudio support
491  if ( clt->ingame && clt->comm_freq != -1 && ( (!un) || (un->GetSerial() != serial) ) )
492  pckt->bc_send( clt->cltadr, clt->tcp_sock );
493  }
494 }
495 
496 /*
497  ***********************************************************************************************
498  **** broadcastSnapshots ****
499  ***********************************************************************************************
500  */
501 #include "lin_time.h"
502 //Broadcast all positions
503 //This function sends interpolated and predicted positions based on the "semi-ping" between the sender clients and the server
504 //the receiver client will only have to interpolate and predict on his own "semi-ping" value
505 //Always UDP.
506 //NETFIXME: May be too big for UDP if there are too many ships. We may want to split these up into reasonable sizes.
507 void ZoneMgr::broadcastSnapshots( bool update_planets )
508 {
509  LI k;
510  //COUT<<"Sending snapshot for ";
511  //int h_length = Packet::getHeaderLength();
512  //Loop for all systems/zones
513  for (ZoneMap::iterator iter = zones.begin(); iter != zones.end(); ++iter) {
514  int totalunits = 0;
515  //Check if system contains player(s)
516  if (true) {
517  ZoneInfo *zi = &(*iter).second;
518 //COUT << "BROADCAST SNAPSHOTS = "<<zone_clients[i]<<" clients in zone "<<i<<" time now: "<<queryTime()<<"; frame time: "<<getNewTime() << endl;
519  //Loop for all the zone's clients
520  for (k = zi->zone_list.begin(); k != zi->zone_list.end(); ++k) {
521  totalunits = 0;
522  ClientPtr cltk( *k );
523  //If that client is ingame we send to it position info
524  //if( true) { // cltk->ingame==true)
525  un_iter iter = ( zi->star_system->getUnitList() ).createIterator();
526  while (*iter) {
527  int nbunits = 0;
528  Packet pckt;
529  NetBuffer netbuf;
530  cltk->versionBuf( netbuf );
531 
532 //COUT << "CLEAN NETBUF" << endl;
533 
534  //This also means clients will receive info about themselves
535  //which they should ignore or take into account sometimes
536  //(according to their ping value)
537  Unit *unit;
538 
539  //Add the client we send snapshot to its own deltatime (semi-ping)
540  netbuf.addFloat( cltk->getDeltatime() );
541 //COUT << " *** deltatime " << cltk->getDeltatime() << endl;
542  //Clients not ingame are removed from the drawList so it is ok not to test that
543  for (; (unit = *iter) != NULL; ++iter) {
544  if ( netbuf.getOffset() > (504-108) && (&cltk->tcp_sock != cltk->lossy_socket) )
545  //Don't want to go over MTU. 512 is UDP maximum and you lose 8 for header.
546  break;
547  ++totalunits;
548  if ( unit->GetSerial() != 0 && unit != cltk->game_unit.GetUnit() ) {
549  //Only send unit that ate UNITPTR and PLANETPTR+NEBULAPTR if update_planets
550  if ( (unit->isUnit() == UNITPTR || unit->isUnit() == ASTEROIDPTR || unit->isUnit()
551  == MISSILEPTR)
552  || ( (unit->isUnit() == PLANETPTR || unit->isUnit() == NEBULAPTR) && update_planets ) ) {
553  ClientState cs( unit );
554 
555  /* TEST if it is a client and then set deltatime */
556  //ClientPtr cltl;
557  //if( (cltl = Server->getClientFromSerial( unit->GetSerial())))
558  //{
559  //cs.setDelay( cltl->getDeltatime() );
560  //This should be moved out of the 'if' when download manager is working
561  //}
562  bool added = addPosition( cltk, netbuf, unit, cs );
563  if (added)
564  ++nbunits;
565  }
566  }
567  }
568  //Send snapshot to client k
569  if (nbunits > 0) {
570  //COUT<<"\tsend update for "<<(p+j)<<" clients"<<endl;
571  pckt.send( CMD_SNAPSHOT, /*nbclients+*/ nbunits,
572  netbuf.getData(), netbuf.getDataLength(),
573  SENDANDFORGET, &(cltk->cltudpadr), *cltk->lossy_socket,
574  __FILE__, PSEUDO__LINE__( 337 ) );
575  }
576  }
577  {
578  Unit *unit;
579  if ( ( unit = cltk->game_unit.GetUnit() ) != NULL ) {
580  Unit *targ = unit->Target();
581  if (targ) {
582  double range = unit->GetComputerData().radar.maxrange;
583  unit->GetComputerData().radar.maxrange *= 1.5; //generous
584  if ( !unit->InRange( targ, false ) )
585  unit->Target( NULL );
586  unit->GetComputerData().radar.maxrange = range;
587  }
588  }
589  }
590  }
591  Unit *unit;
592  //Clients not ingame are removed from the drawList so it is ok not to test that
593  for (un_iter iter = ( zi->star_system->getUnitList() ).createIterator(); (unit = *iter) != NULL; ++iter) {
594  clsptr typ = unit->isUnit();
595  if ( (typ == UNITPTR || typ == MISSILEPTR) && vsrandom.genrand_int31()%(totalunits*10+1) == 1 )
596  unit->damages = 0xffff;
597  if (unit->damages) {
598  for (k = zi->zone_list.begin(); k != zi->zone_list.end(); k++) {
599  //Each damage sent in a separate UDP packet.
600  NetBuffer netbuf;
601  ClientPtr cltk( *k );
602  cltk->versionBuf( netbuf );
603  netbuf.addFloat( cltk->getDeltatime() );
604  netbuf.addChar( ZoneMgr::DamageUpdate );
605  netbuf.addShort( unit->GetSerial() );
606  addDamage( netbuf, unit );
607  Packet pckt;
608  pckt.send( CMD_SNAPSHOT, 1,
609  netbuf.getData(), netbuf.getDataLength(),
610  SENDANDFORGET, &(cltk->cltudpadr), *cltk->lossy_socket,
611  __FILE__, PSEUDO__LINE__( 522 ) );
612  }
613  }
614  unit->damages = Unit::NO_DAMAGE;
615  }
616  }
617  }
618 }
619 bool Nearby( ClientPtr clt, Unit *un )
620 {
621  Unit *parent = clt->game_unit.GetUnit();
622  if (parent) {
623  if (un == parent) return true;
624  double mm;
625  if ( !parent->InRange( un, mm, false, false, true ) ) {
626  static double always_send_range =
627  XMLSupport::parse_float( vs_config->getVariable( "server", "visible_send_range", "1000" ) );
628  if (parent->computer.radar.maxrange >= always_send_range)
629  return false;
630  {
631  QVector dist = ( un->Position()-parent->Position() );
632  if (dist.Dot( dist ) >= always_send_range*always_send_range)
633  return false;
634  }
635  }
636  static double maxrange = XMLSupport::parse_float( vs_config->getVariable( "server", "max_send_range", "1e21" ) );
637  if (mm > maxrange)
638  return false;
639  } else {return false; } return true;
640 }
641 bool ZoneMgr::addPosition( ClientPtr client, NetBuffer &netbuf, Unit *un, ClientState &un_cs )
642 {
643  bool dodamage = false; //Now done in separate packets in broadcastSnapshots.
644  //This test may be wrong for server side units -> may cause more traffic than needed
645  if (1 /* !(un->old_state.getPosition()==un->curr_physical_state.position) ||
646  * !(un->old_state.getOrientation()==un->curr_physical_state.orientation) */) {
647  //Unit 'un' can see Unit 'iter'
648  //For now only check if the 'iter' client is in front of Unit 'un')
649  if (1 /*(distance = this->isVisible( source_orient, source_pos, target_pos)) > 0*/) {
650  //Test if client 'l' is far away from client 'k' = test radius/distance<=X
651  //So we can send only position
652  //Here distance should never be 0
653  //ratio = radius/distance;
654  if (un->damages || Nearby( client, un ) /* ratio > XX client not too far */) {
655  unsigned char type = ZoneMgr::FullUpdate;
656  if (dodamage && un->damages)
657  type |= ZoneMgr::DamageUpdate;
658  //Always send spec info for now...
659  if (client->netversion > 4960)
660  if (un_cs.getSpecMult() >= 1.0)
661  type |= ZoneMgr::SPECUpdate;
662 //COUT << " *** FullUpdate ser=" << un->GetSerial() << " cs=" << un_cs << endl;
663  //Mark as position+orientation+velocity update
664  netbuf.addChar( type );
665  netbuf.addShort( un->GetSerial() );
666  //Put the current client state in
667  netbuf.addClientState( un_cs );
668  //Throw in some other cheap but useful info.
669  netbuf.addFloat( un->energy );
670  //Increment the number of clients we send full info about
671  if (type&ZoneMgr::SPECUpdate) {
672  netbuf.addFloat( un_cs.getSpecRamp() );
673  netbuf.addFloat( un_cs.getSpecMult() );
674  }
675  if (dodamage && un->damages)
676  addDamage( netbuf, un );
677  }
678  //Here find a condition for which sending only position would be enough
679  else if (0 /* ratio>=1 far but still visible */) {
680 //COUT << " *** PosUpdate ser=" << un->GetSerial()
681 //<< " pos=" << un_cs.getPosition().i
682 //<< "," << un_cs.getPosition().j
683 //<< "," << un_cs.getPosition().k << endl;
684  //Mark as position update only
685  netbuf.addChar( ZoneMgr::PosUpdate );
686  //Add the client serial
687  netbuf.addShort( un->GetSerial() );
688  netbuf.addQVector( un_cs.getPosition() );
689  //Increment the number of clients we send limited info about
690  } else {
691  static int i = 0;
692  if ( (i++)%8192 == 0 )
693  COUT<<"PosUpdate not sent (too far away) "<<un->name<<" #"<<un->GetSerial()<<endl;
694  return false;
695  }
696  } else {
697  COUT<<"Client counted but not sent because of distance!"<<endl;
698  return false;
699  }
700  } else {
701  COUT<<"Client counted but not sent because of position/orientation test!"<<endl;
702  return false;
703  }
704  return true;
705 }
706 
707 /*
708  ***********************************************************************************************
709  **** broadcastDamage ****
710  ***********************************************************************************************
711  */
712 
713 //Broadcast all damages
714 //NETFIXME: May be too big for UDP.
716 {
717  LI k;
718  NetBuffer netbuf;
719  //COUT<<"Sending snapshot for ";
720  //int h_length = Packet::getHeaderLength();
721  //Loop for all systems/zones
722  for (ZoneMap::iterator iter = zones.begin(); iter != zones.end(); ++iter) {
723  int totalunits = 0;
724  //Check if system is non-empty
725  if (true) {
726  ZoneInfo *zi = &(*iter).second;
727  /************* Second method : send independently to each client a buffer of its zone ***************/
728  //It allows to check (for a given client) if other clients are far away (so we can only
729  //send position, not orientation and stuff) and if other clients are visible to the given
730  //client.
731  //int nbclients = 0;
732  Packet pckt;
733  //cerr<<"BROADCAST DAMAGE = "<<zone_clients[i]<<" clients in zone "<<i<<endl;
734  //Loop for all the zone's clients
735  for (k = zi->zone_list.begin(); k != zi->zone_list.end(); k++) {
736  int nbunits = 0;
737  totalunits = 0;
738  ClientPtr cp( *k );
739  cp->versionBuf( netbuf );
740  if (cp->ingame) {
741  Unit *unit;
742  //Clients not ingame are removed from the drawList so it is ok not to test that
743  for (un_iter iter = ( zi->star_system->getUnitList() ).createIterator(); (unit = *iter) != NULL; ++iter)
744  if (unit->GetSerial() != 0) {
745  if (unit->damages) {
746  //Add the client serial
747  netbuf.addSerial( unit->GetSerial() );
748  addDamage( netbuf, unit );
749  ++nbunits;
750  }
751  ++totalunits;
752  }
753  //NETFIXME: Should damage updates be UDP or TCP?
754  //Send snapshot to client k
755  if (netbuf.getDataLength() > 0) {
756  pckt.send( CMD_SNAPDAMAGE, /*nbclients+*/ nbunits,
757  netbuf.getData(), netbuf.getDataLength(),
758  SENDANDFORGET, &(cp->cltudpadr), *cp->lossy_socket,
759  __FILE__, PSEUDO__LINE__( 442 ) );
760  }
761  }
762  }
763  {
764  Unit *unit;
765  //Clients not ingame are removed from the drawList so it is ok not to test that
766  for (un_iter iter = ( zi->star_system->getUnitList() ).createIterator(); (unit = *iter) != NULL; ++iter) {
767  unit->damages = Unit::NO_DAMAGE;
768  clsptr typ = unit->isUnit();
769  if ( (typ == UNITPTR || typ == MISSILEPTR) && vsrandom.genrand_int31()%(totalunits*10+1) == 1 )
770  unit->damages = 0xffff&(~Unit::COMPUTER_DAMAGED);
771  }
772  }
773  }
774  }
775 }
776 
777 void ZoneMgr::addDamage( NetBuffer &netbuf, Unit *un )
778 {
779  unsigned int it = 0;
780 
781  //Add the damage flag
782  unsigned short damages = un->damages;
783  if ( (damages&Unit::COMPUTER_DAMAGED) && (damages&Unit::LIMITS_DAMAGED) )
784  damages &= (~Unit::MOUNT_DAMAGED);
785  if ( netbuf.version() < 4500 && (damages&Unit::LIMITS_DAMAGED) )
786  //Makes it too big with a bunch of 32-bit floats.
787  damages &= (~Unit::COMPUTER_DAMAGED);
788  netbuf.addShort( damages );
789  //cout << "Sent damage " <<damages<<" for unit "<<un->GetSerial()<<" ("<<un->name<<")"<<endl;
790  //Put the altered stucts after the damage enum flag
791  if (damages&Unit::SHIELD_DAMAGED)
792  netbuf.addShield( un->shield );
793  if (damages&Unit::ARMOR_DAMAGED) {
794  netbuf.addArmor( un->armor );
795  netbuf.addFloat( un->hull );
796  }
797  if (damages&Unit::COMPUTER_DAMAGED) {
798  netbuf.addChar( un->computer.itts );
799  netbuf.addChar( un->computer.radar.UseFriendFoe() ? 1 : 0 );
800  netbuf.addFloat( un->limits.retro );
801  netbuf.addFloat( un->computer.radar.maxcone );
802  netbuf.addFloat( un->computer.radar.lockcone );
803  netbuf.addFloat( un->computer.radar.trackingcone );
804  netbuf.addFloat( un->computer.radar.maxrange );
805  unsigned char c = 1+UnitImages< void >::NUMGAUGES+MAXVDUS;
806  netbuf.addChar( c );
807  for (it = 0; it < c; it++)
808  netbuf.addFloat8( un->pImage->cockpit_damage[it] );
809  }
810  if (damages&Unit::MOUNT_DAMAGED) {
811  netbuf.addShort( un->pImage->ecm );
812  netbuf.addShort( un->mounts.size() );
813  for (it = 0; it < un->mounts.size(); it++) {
814  netbuf.addChar( (char) un->mounts[it].status );
815 
816  netbuf.addInt32( un->mounts[it].ammo );
817  netbuf.addFloat( un->mounts[it].time_to_lock );
818  netbuf.addShort( un->mounts[it].size );
819  }
820  }
821  if (damages&Unit::CARGOFUEL_DAMAGED) {
822  netbuf.addFloat( un->FuelData() );
823  netbuf.addFloat( un->AfterburnData() );
824  netbuf.addFloat( un->pImage->CargoVolume );
825  netbuf.addFloat( un->pImage->UpgradeVolume );
826 //for( it=0; it<un->pImage->cargo.size(); it++)
827 //netbuf.addInt32( un->pImage->cargo[it].quantity);
828  }
829  if (damages&Unit::JUMP_DAMAGED) {
830  netbuf.addChar( un->shield.leak );
831  netbuf.addFloat( un->shield.recharge );
832  netbuf.addFloat( un->EnergyRechargeData() );
833  netbuf.addFloat( un->MaxEnergyData() );
834  netbuf.addFloat( un->jump.energy ); //NETFIXME: Add insys energy too?
835  netbuf.addChar( un->jump.damage );
836  netbuf.addChar( un->pImage->repair_droid );
837  }
838  if (damages&Unit::CLOAK_DAMAGED) {
839  netbuf.addInt32( un->cloaking );
840  netbuf.addFloat( un->pImage->cloakenergy );
841  netbuf.addInt32( un->cloakmin );
842  netbuf.addInt32( un->pImage->cloakrate );
843  }
844  if (damages&Unit::LIMITS_DAMAGED) {
845  netbuf.addFloat( un->computer.max_pitch_down );
846  netbuf.addFloat( un->computer.max_pitch_up );
847  netbuf.addFloat( un->computer.max_yaw_left );
848  netbuf.addFloat( un->computer.max_yaw_right );
849  netbuf.addFloat( un->computer.max_roll_left );
850  netbuf.addFloat( un->computer.max_roll_right );
851  netbuf.addFloat( un->limits.roll );
852  netbuf.addFloat( un->limits.yaw );
853  netbuf.addFloat( un->limits.pitch );
854  netbuf.addFloat( un->limits.lateral );
855  }
856 }
857 
858 /*
859  ***********************************************************************************************
860  **** isVisible ****
861  ***********************************************************************************************
862  */
863 
864 double ZoneMgr::isVisible( Quaternion orient, QVector src_pos, QVector tar_pos )
865 {
866  double dotp = 0;
867  Matrix m;
868 
869  orient.to_matrix( m );
870  QVector src_tar( m.getR() );
871 
872  src_tar = tar_pos-src_pos;
873  dotp = DotProduct( src_tar, (QVector) orient.v );
874 
875  return dotp;
876 }
877 
879 {
880  cout<<star_system->getFileName()<<"(zone "<<zonenum<<")"<<endl;
881  for (ClientList::iterator ci = zone_list.begin(); ci != zone_list.end(); ++ci) {
882  Client *clt = (*ci).get();
883  if (!clt) continue;
884  Unit *un = clt->game_unit.GetUnit();
885  if (un && _Universe->isPlayerStarship( un ) == NULL)
886  displayUnitInfo( un, clt->callsign, " CltNPC " );
887  }
888  un_iter iter = ( star_system->getUnitList() ).createIterator();
889  while (Unit*un = *iter) {
890  char name[15] = " NPC ";
891  string callsign;
892  int cp;
893  if ( ( cp = _Universe->whichPlayerStarship( un ) ) != -1 ) {
894  sprintf( name, "*Plr% 3d ", cp );
895  callsign = _Universe->AccessCockpit( cp )->savegame->GetCallsign();
896  }
897  displayUnitInfo( un, callsign, name );
898  ++iter;
899  }
900 }
902 {
903  cout<<"----- Active Systems:"<<endl;
904  for (ZoneMap::iterator iter = zones.begin(); iter != zones.end(); ++iter) {
905  ZoneInfo *zi = &( (*iter).second );
906  StarSystem *ss = zi->star_system;
907  for (unsigned int i = 0; i < _Universe->numPlayers(); ++i) {
908  Cockpit *cp = _Universe->AccessCockpit( i );
909  if (cp->activeStarSystem != ss)
910  continue;
911  Unit *un;
912  char name[15];
913  if ( !cp->GetParent() ) {
914  sprintf( name, "*Plr% 3d ", i );
915  displayUnitInfo( NULL, cp->savegame->GetCallsign(), name );
916  }
917  }
918  zi->display();
919  }
920 }
921 /*
922  ***********************************************************************************************
923  **** displayStats ****
924  ***********************************************************************************************
925  */
926 
928 {
929  cout<<"\tStar system stats"<<endl;
930  cout<<"\t-----------------"<<endl;
931  for (ZoneMap::const_iterator iter = zones.begin(); iter != zones.end(); ++iter) {
932  const ZoneInfo *zi = &( (*iter).second );
933  cout<<"\t\tStar system "<<(zi->zonenum)<<" = "<<zi->star_system->getName()<<endl;
934  cout<<"\t\t\tNumber of clients :\t"<<zi->zone_clients<<endl;
935  //cout<<"\t\t\tNumber of units :\t"<<zone_units[i]<<endl;
936  }
937 }
938 
939 /*
940  ***********************************************************************************************
941  **** displayMemory ****
942  ***********************************************************************************************
943  */
944 
946 {
947  /*
948  * unsigned int i;
949  * int memory_use=0;
950  * int memclient=0, memunit=0, memvars=0;
951  * cout<<"\tStar system memory usage (do not count struct pointed by pointer)"<<endl;
952  * cout<<"\t-----------------------------------------------------------------"<<endl;
953  * for( i=0; i<zone_list.size(); i++)
954  * {
955  *
956  * cout<<"\t\tStar system "<<i<<" = \"<<_Universe->star_system[i]->getName()"<<"\""<<endl;
957  * memclient = zone_clients[i]*sizeof( class Client);
958  * //memunit = zone_units[i]*sizeof( class Unit);
959  * memvars = zone_clients[i]*sizeof( int)*2;
960  * cout<<"\t\t\tMemory for clients :\t"<<(memclient/1024)<<" KB ("<<memclient<<" bytes)"<<endl;
961  * cout<<"\t\t\tMemory for units :\t"<<(memunit/1024)<<" KB ("<<memunit<<" bytes)"<<endl;
962  * cout<<"\t\t\tMemory for variables :\t"<<(memvars/1024)<<" KB ("<<memvars<<" bytes)"<<endl;
963  * memory_use += (memclient+memunit+memvars);
964  * }
965  *
966  * return memory_use;
967  */
968 
969  //Not bothering to fix up this function at the moment -Patrick
970  return -1;
971 }
972 
973 std::string ZoneMgr::Systems::insert( std::string sysname, std::string system )
974 {
975  if (sysname != "" && system != "")
976  _map.insert( SystemPair( sysname, system ) );
977  return sysname;
978 }
979 
980 std::string ZoneMgr::Systems::get( std::string sysname )
981 {
982  SystemIt it = _map.find( sysname );
983  if ( it == _map.end() ) return string( "" );
984  return it->second;
985 }
986 
987 bool ZoneMgr::Systems::remove( std::string sysname )
988 {
989  size_t s = _map.erase( sysname );
990  if (s == 0) return false;
991  return true;
992 }
993 
994 /*** This is a copy of GFXSphereInFrustum from gl_matrix_hack.cpp avoiding
995  * linking with a LOT of unecessary stuff
996  */
997 
998 /*
999  * float ZoneMgr::sphereInFrustum( const Vector &Cnt, float radius)
1000  * {
1001  * float frust [6][4];
1002  * int p;
1003  * float d;
1004  * for( p = 0; p < 5; p++ )//does not evaluate for yon
1005  * {
1006  * d = f[p][0] * Cnt.i + f[p][1] * Cnt.j + f[p][2] * Cnt.k + f[p][3];
1007  * if( d <= -radius )
1008  * return 0;
1009  * }
1010  * return d;
1011  * }
1012  */
1013