vegastrike  0.5.1.r1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
savegame.cpp
Go to the documentation of this file.
1 #include "cs_python.h"
2 #include "cmd/unit_generic.h"
3 #include "hashtable.h"
4 #include <float.h>
5 #include "vsfilesystem.h"
6 #include <vector>
7 #include <string>
8 #include "configxml.h"
9 #include "vs_globals.h"
10 #include "savegame.h"
11 #include "load_mission.h"
12 #include <algorithm>
13 #include "cmd/script/mission.h"
14 #include "gfx/cockpit_generic.h"
15 #include "networking/const.h"
16 #include "vsfilesystem.h"
17 #include "cmd/fg_util.h"
18 
19 #include "options.h"
20 
22 
23 using namespace VSFileSystem;
24 using std::vector;
25 using std::string;
26 using std::cout;
27 using std::endl;
28 using std::allocator;
29 using std::cerr;
30 
31 std::string CurrentSaveGameName = "";
32 std::string GetHelperPlayerSaveGame( int num )
33 {
34  if (Network == NULL) {
35  if (CurrentSaveGameName.length() > 0) {
36  if (game_options.remember_savegame) {
37  VSFile f;
38  VSError err = f.OpenCreateWrite( "save.4.x.txt", UnknownFile );
39  if (err <= Ok) {
41  f.Close();
42  }
43  }
44  if (num != 0)
46  return CurrentSaveGameName;
47  }
48  cout<<"Hi helper play "<<num<<endl;
49  static string *res = NULL;
50  if (res == NULL) {
51  res = new std::string;
52  VSFile f;
53  //TRY TO OPEN THE save.4.x.txt FILE WHICH SHOULD CONTAIN THE NAME OF THE SAVE TO USE
54  VSError err = f.OpenReadOnly( "save.4.x.txt", UnknownFile ); // DELETE .4.x no longer used
55  if (err > Ok) {
56  //IF save.4.x.txt DOES NOT EXIST WE CREATE ONE WITH "default" AS SAVENAME
57  err = f.OpenCreateWrite( "save.4.x.txt", UnknownFile );
58  if (err <= Ok) {
59  f.Write( game_options.new_game_save_name.c_str(), game_options.new_game_save_name.length() );
60  f.Write( "\n", 1 );
61  f.Close();
62  } else {
63  fprintf( stderr, "!!! ERROR : Creating default save.4.x.txt file : %s\n", f.GetFullPath().c_str() );
64  exit( 1 );
65  }
66  err = f.OpenReadOnly( "save.4.x.txt", UnknownFile );
67  if (err > Ok) {
68  fprintf( stderr, "!!! ERROR : Opening the default save we just created\n" );
69  exit( 1 );
70  }
71  }
72  if (err <= Ok) {
73  long length = f.Size();
74  if (length > 0) {
75  char *temp = (char*) malloc( length+1 );
76  temp[length] = '\0';
77  f.Read( temp, length );
78  bool end = true;
79  for (int i = length-1; i >= 0; i--) {
80  if (temp[i] == '\r' || temp[i] == '\n')
81  temp[i] = (end ? '\0' : '_');
82  else if (temp[i] == '\0' || temp[i] == ' ' || temp[i] == '\t')
83  temp[i] = (end ? '\0' : '_');
84  else
85  end = false;
86  }
87  *res = (temp);
88  free( temp );
89  }
90  f.Close();
91  }
92  if ( game_options.remember_savegame && !res->empty() ) {
93  //Set filetype to Unknown so that it is searched in homedir/
94  if (*res->begin() == '~') {
95  err = f.OpenCreateWrite( "save.4.x.txt", VSFileSystem::UnknownFile );
96  if (err <= Ok) {
97  for (unsigned int i = 1; i < res->length(); i++) {
98  char cc = *(res->begin()+i);
99  f.Write( &cc, sizeof (char) );
100  }
101  char cc = 0;
102  f.Write( &cc, sizeof (char) );
103  f.Close();
104  }
105  }
106  }
107  }
108  if ( num == 0 || res->empty() ) {
109  cout<<"Here";
110  return *res;
111  }
112  return (*res)+XMLSupport::tostring( num );
113  } else {
114  //Return "" so that the filename argument to ParseSavegame will be used
115  return "";
116  }
117 }
118 
119 std::string GetWritePlayerSaveGame( int num )
120 {
121  string ret = GetHelperPlayerSaveGame( num );
122  if ( !ret.empty() )
123  if (*ret.begin() == '~')
124  return ret.substr( 1, ret.length() );
125  return ret;
126 }
127 
128 std::string GetReadPlayerSaveGame( int num )
129 {
130  string ret = GetHelperPlayerSaveGame( num );
131  if ( !ret.empty() )
132  if (*ret.begin() == '~')
133  return "";
134  return ret;
135 }
136 
137 //Used only to copy a savegame to a different named one
138 void SaveFileCopy( const char *src, const char *dst )
139 {
140  if (dst[0] != '\0' && src[0] != '\0') {
141  VSFile f;
142  VSError err = f.OpenReadOnly( src, SaveFile );
143  if (err <= Ok) {
144  string savecontent = f.ReadFull();
145  f.Close();
146  err = f.OpenCreateWrite( dst, SaveFile );
147  if (err <= Ok) {
148  f.Write( savecontent );
149  f.Close();
150  } else {
151  fprintf( stderr, "WARNING : couldn't open savegame to copy to : %s as SaveFile", dst );
152  }
153  } else {
154  fprintf( stderr, "WARNING : couldn't find the savegame to copy : %s as SaveFile", src );
155  }
156  }
157 }
158 
160 {
161 public:
162  typedef std::map< string, vector< std::string > >MSD;
164 };
165 
167 {
168 public:
169  typedef vsUMap< string, vector< float > >MFD;
171 };
172 
173 SaveGame::SaveGame( const std::string &pilot )
174 {
175  callsign = pilot;
176  ForceStarSystem = string( "" );
177  PlayerLocation.Set( FLT_MAX, FLT_MAX, FLT_MAX );
178  missionstringdata = new MissionStringDat;
179  missiondata = new MissionFloatDat;
180 }
181 
183 {
184  delete missionstringdata;
185  delete missiondata;
186 }
187 
188 void SaveGame::SetStarSystem( string sys )
189 {
190  ForceStarSystem = sys;
191 }
192 
194 {
195  return ForceStarSystem;
196 }
197 
199 {
200  return ForceStarSystem;
201 }
202 
203 void SaveGame::SetPlayerLocation( const QVector &v )
204 {
205  if ( ( FINITE( v.i ) && FINITE( v.j ) && FINITE( v.k ) ) ) {
206  PlayerLocation = v;
207  } else {
208  VSFileSystem::vs_fprintf( stderr, "NaN ERROR saving unit\n" );
209  assert( FINITE( v.i ) && FINITE( v.j ) && FINITE( v.k ) );
210  PlayerLocation.Set( 1, 1, 1 );
211  }
212 }
213 
215 {
216  return PlayerLocation;
217 }
218 
219 void SaveGame::RemoveUnitFromSave( long address ) // DELETE ? unused function?
220 {
221 }
222 
223 string SaveGame::WriteNewsData()
224 {
225  string ret( "" );
226  gameMessage last;
227  vector< gameMessage >tmp;
228  int i = 0;
229  vector< string >newsvec;
230  newsvec.push_back( "news" );
231  while ( ( mission->msgcenter->last( i++, last, newsvec ) ) )
232  tmp.push_back( last );
233  ret += XMLSupport::tostring( i )+"\n";
234  for (int j = tmp.size()-1; j >= 0; j--) {
235  char *msg = strdup( tmp[j].message.get().c_str() );
236  int k = 0;
237  while (msg[k]) {
238  if (msg[k] == '\r')
239  msg[k] = ' ';
240  if (msg[k] == '\n')
241  msg[k] = '/';
242  k++;
243  }
244  ret += string( msg )+"\n";
245  free( msg );
246  }
247  return ret;
248 }
249 
250 vector< string >parsePipedString( string s )
251 {
252  string::size_type loc;
253  vector< string > ret;
254  while ( ( loc = s.find( "|" ) ) != string::npos ) {
255  ret.push_back( s.substr( 0, loc ) );
256  cout<<"Found ship named : "<<s.substr( 0, loc )<<endl;
257  s = s.substr( loc+1 );
258  }
259  if ( s.length() ) {
260  ret.push_back( s );
261  cout<<"Found ship named : "<<s<<endl;
262  }
263  return ret;
264 }
265 
266 string createPipedString( vector< string >s )
267 {
268  string ret;
269  for (unsigned int i = 0; i < s.size()-1; i++)
270  ret += s[i]+"|";
271  if ( s.size() )
272  ret += s.back();
273  return ret;
274 }
275 
276 void CopySavedShips( std::string filename, int player_num, const std::vector< std::string > &starships, bool load )
277 {
278  for (unsigned int i = 0; i < starships.size(); i += 2) {
279  if (i == 2) i = 1;
280  VSFile src, dst;
281  string srcnam = filename;
282  string dstnam = GetWritePlayerSaveGame( player_num );
283  string tmp;
284  if (load) {
285  tmp = srcnam;
286  srcnam = dstnam;
287  dstnam = tmp;
288  }
289  VSError e = src.OpenReadOnly( srcnam+"/"+starships[i]+".csv", UnitSaveFile );
290  if (e <= Ok) {
292  VSError f = dst.OpenCreateWrite( dstnam+"/"+starships[i]+".csv", UnitFile );
293  if (f <= Ok) {
294  string srcdata = src.ReadFull();
295  dst.Write( srcdata );
296  } else {
297  printf( "Error: Cannot Copy Unit %s from save file %s to %s\n",
298  starships[i].c_str(),
299  srcnam.c_str(),
300  dstnam.c_str() );
301  }
302  } else {
303  printf( "Error: Cannot Open Unit %s from save file %s.\n",
304  starships[i].c_str(),
305  srcnam.c_str() );
306  }
307  }
308 }
309 
310 void WriteSaveGame( Cockpit *cp, bool auto_save )
311 {
312  int player_num = 0;
313  for (unsigned int kk = 0; kk < _Universe->numPlayers(); ++kk)
314  if (_Universe->AccessCockpit( kk ) == cp)
315  player_num = kk;
316  Unit *un = cp->GetSaveParent();
317  if (!un)
318  return;
319  if (un->GetHull() > 0) {
320  vector< string > packedInfo;
321  cp->PackUnitInfo(packedInfo);
322 
323  cp->savegame->WriteSaveGame( cp->activeStarSystem->getFileName().c_str(),
324  un->LocalPosition(), cp->credits, packedInfo, auto_save ? -1 : player_num );
325  un->WriteUnit( cp->GetUnitModifications().c_str() );
326  if (GetWritePlayerSaveGame( player_num ).length() && !auto_save) {
327  cp->savegame->SetSavedCredits( _Universe->AccessCockpit()->credits );
328  cp->savegame->SetStarSystem( cp->activeStarSystem->getFileName() );
329  cp->savegame->SetPlayerLocation( un->LocalPosition() );
330  CopySavedShips( cp->GetUnitModifications(), player_num, packedInfo, false );
331  }
332  }
333 }
334 
335 int hopto( char *buf, char endln, char endln2, int readlen )
336 {
337  if (endln == ' ' || endln2 == ' ')
338  while (buf[readlen] && buf[readlen] == ' ')
339  readlen++;
340  for (; buf[readlen] != 0 && buf[readlen] != endln && buf[readlen] != endln2; readlen++)
341  ;
342  if ( (buf[readlen] && buf[readlen] == endln) || buf[readlen] == endln2 )
343  readlen++;
344  return readlen;
345 }
346 
347 void SaveGame::ReadNewsData( char* &buf, bool just_skip )
348 {
349  int numnews;
350  int i = 0;
351  vector< string >n00s;
352  n00s.push_back( "news" );
353  vector< string >nada;
354  mission->msgcenter->clear( n00s, nada );
355  int offset = hopto( buf, '\n', '\n', 0 );
356  if (offset > 0) {
357  sscanf( buf, "%d\n", &numnews );
358  buf += offset;
359  for (i = 0; i < numnews; i++) {
360  offset = hopto( buf, '\n', '\n', 0 );
361  if (offset > 0)
362  buf[offset-1] = 0;
363  int l = 0;
364  for (l = 0; l < offset-1; l++)
365  if (buf[l] != '\r' && buf[l] != '\n')
366  break;
367  if (!just_skip && buf[l] != '\r' && buf[l] != '\n' && buf[l])
368  mission->msgcenter->add( "game", "news", buf+l );
369  buf += offset;
370  }
371  }
372 }
373 
374 void SaveGame::AddUnitToSave( const char *filename, int type, const char *faction, long address )
375 {
376  if ( game_options.Drone.compare( filename ) )
377  RemoveUnitFromSave( address );
378 }
379 
380 std::vector< float >& SaveGame::getMissionData( const std::string &magic_number )
381 {
382  return missiondata->m[magic_number];
383 }
384 
385 const std::vector< float >& SaveGame::readMissionData( const std::string &magic_number ) const
386 {
387  static const std::vector< float > empty;
388  MissionFloatDat::MFD::const_iterator it = missiondata->m.find( magic_number );
389  return ( it == missiondata->m.end() ) ? empty : it->second;
390 }
391 
392 unsigned int SaveGame::getMissionDataLength( const std::string &magic_number ) const
393 {
394  MissionFloatDat::MFD::const_iterator it = missiondata->m.find( magic_number );
395  return ( it == missiondata->m.end() ) ? 0 : it->second.size();
396 }
397 
398 const std::vector< string >& SaveGame::readMissionStringData( const std::string &magic_number ) const
399 {
400  static const std::vector< string > empty;
401  MissionStringDat::MSD::const_iterator it = missionstringdata->m.find( magic_number );
402  return ( it == missionstringdata->m.end() ) ? empty : it->second;
403 }
404 
405 std::vector< string >& SaveGame::getMissionStringData( const std::string &magic_number )
406 {
407  return missionstringdata->m[magic_number];
408 }
409 
410 unsigned int SaveGame::getMissionStringDataLength( const std::string &magic_number ) const
411 {
412  MissionStringDat::MSD::const_iterator it = missionstringdata->m.find( magic_number );
413  return ( it == missionstringdata->m.end() ) ? 0 : it->second.size();
414 }
415 
416 template < class MContainerType >
417 void RemoveEmpty( MContainerType &t )
418 {
419  typename MContainerType::iterator i;
420  for (i = t.begin(); i != t.end();)
421  if ( i->second.empty() )
422  t.erase( i++ );
423 
424  else
425  ++i;
426 }
427 
428 string SaveGame::WriteMissionData()
429 {
430  string ret( " " );
431  RemoveEmpty< MissionFloatDat::MFD > ( missiondata->m );
432  ret += XMLSupport::tostring( (int) missiondata->m.size() );
433  for (MissionFloatDat::MFD::iterator i = missiondata->m.begin(); i != missiondata->m.end(); i++) {
434  unsigned int siz = (*i).second.size();
435 
436  // Escape spaces within the key by replacing them with a special char ¬
437  string k = (*i).first;
438  { for (size_t i=0,len=k.length(); i<len; ++i)
439  if (k[i] == ' ') k[i] = '`'; }
440 
441  ret += string( "\n" )+k+string( " " )+XMLSupport::tostring( siz )+" ";
442  for (unsigned int j = 0; j < siz; j++)
443  ret += XMLSupport::tostring( (*i).second[j] )+" ";
444  }
445  return ret;
446 }
447 
448 std::string scanInString( char* &buf )
449 {
450  std::string str;
451  while ( *buf && isspace( *buf ) )
452  buf++;
453  char *start = buf;
454  while ( *buf && ( !isspace( *buf ) ) )
455  buf++;
456  str.resize(buf - start);
457  for (size_t i=0; start < buf; ++i)
458  str[i] = *(start++);
459  return str;
460 }
461 
462 void SaveGame::ReadMissionData( char* &buf, bool select_data, const std::set< std::string > &select_data_filter )
463 {
464  missiondata->m.clear();
465  int mdsize;
466  char *buf2 = buf;
467  sscanf( buf2, " %d ", &mdsize );
468  //Put ptr to point after the number we just read
469  buf2 += hopto( buf2, ' ', '\n', 0 );
470  for (int i = 0; i < mdsize; i++) {
471  int md_i_size;
472  string mag_num( scanInString( buf2 ) );
473 
474  // Unescape spaces within the key by replacing the special char ¬
475  { for (size_t i=0,len=mag_num.length(); i<len; ++i)
476  if (mag_num[i] == '`') mag_num[i] = ' '; }
477 
478  sscanf( buf2, "%d ", &md_i_size );
479  //Put ptr to point after the number we just read
480  buf2 += hopto( buf2, ' ', '\n', 0 );
481  vector< float > *vecfloat = 0;
482  bool skip = true;
483  if ( !select_data || select_data_filter.count( mag_num ) ) {
484  vecfloat = &missiondata->m[mag_num];
485  vecfloat->clear();
486  vecfloat->reserve(md_i_size);
487  skip = false;
488  }
489  for (int j = 0; j < md_i_size; j++) {
490  if (!skip) {
491  double float_val = atof(buf2);
492  vecfloat->push_back( float_val );
493  }
494  //Put ptr to point after the number we just read
495  buf2 += hopto( buf2, ' ', '\n', 0 );
496  }
497  }
498  buf = buf2;
499 }
500 
501 string AnyStringScanInString( char* &buf )
502 {
503  unsigned int size = 0;
504  bool found = false;
505  while ( (*buf) && ( (*buf) != ' ' || (!found) ) ) {
506  if ( (*buf) >= '0' && (*buf) <= '9' ) {
507  size *= 10;
508  size += (*buf)-'0';
509  found = true;
510  }
511  buf++;
512  }
513  if (*buf)
514  buf++;
515  string ret;
516  ret.resize( size );
517  unsigned int i = 0;
518  while (i < size && *buf)
519  ret[i++] = *(buf++);
520  return ret;
521 }
522 
523 void AnyStringSkipInString( char* &buf )
524 {
525  unsigned int size = 0;
526  bool found = false;
527  while ( (*buf) && ( (*buf) != ' ' || (!found) ) ) {
528  if ( (*buf) >= '0' && (*buf) <= '9' ) {
529  size *= 10;
530  size += (*buf)-'0';
531  found = true;
532  }
533  buf++;
534  }
535  if (*buf)
536  buf++;
537  unsigned int i = 0;
538  while (i < size && *buf)
539  ++i, ++buf;
540 }
541 
542 string AnyStringWriteString( string input )
543 {
544  return XMLSupport::tostring( (int) input.length() )+" "+input;
545 }
546 
547 void SaveGame::ReadMissionStringData( char* &buf, bool select_data, const std::set< std::string > &select_data_filter )
548 {
549  missionstringdata->m.clear();
550  int mdsize;
551  char *buf2 = buf;
552  sscanf( buf2, " %d ", &mdsize );
553  //Put ptr to point after the number we just read
554  buf2 += hopto( buf2, ' ', '\n', 0 );
555  for (int i = 0; i < mdsize; i++) {
556  int md_i_size;
557  string mag_num( AnyStringScanInString( buf2 ) );
558  md_i_size = strtol( buf2, (char**) NULL, 10 );
559  //Put ptr to point after the number we just read
560  buf2 += hopto( buf2, ' ', '\n', 0 );
561  vector< string > *vecstring = 0;
562  bool skip = true;
563  if ( !select_data || select_data_filter.count( mag_num ) ) {
564  vecstring = &missionstringdata->m[mag_num];
565  vecstring->clear();
566  vecstring->reserve(md_i_size);
567  skip = false;
568  }
569  for (int j = 0; j < md_i_size; j++) {
570  if (skip)
571  AnyStringSkipInString( buf2 );
572 
573  else
574  vecstring->push_back( AnyStringScanInString( buf2 ) );
575  }
576  }
577  buf = buf2;
578  this->PurgeZeroStarships();
579 }
580 
581 void SaveGame::PurgeZeroStarships() // DELETE unused function?
582 {
583  for (MissionStringDat::MSD::iterator i = missionstringdata->m.begin(), ie = missionstringdata->m.end(); i != ie; ++i)
584  if ( fg_util::IsFGKey( i->first ) )
585  if ( fg_util::CheckFG( i->second ) )
586  {
587  //printf( "correcting flightgroup %s to have right landed ships\n", i->first.c_str() );
588  }
589 }
590 
591 static inline void PushBackUInt( unsigned int i, vector< char > &ret )
592 {
593  char tmp[32];
594  if (!i) {
595  ret.push_back( '0' );
596  } else {
597  unsigned int p = 0, q = ret.size();
598  while (i) {
599  tmp[p++] = (i%10+'0');
600  i /= 10;
601  }
602  ret.resize( q+p );
603  while (p)
604  ret[q++] = tmp[--p];
605  }
606 }
607 
608 static inline void PushBackChars( const char *c, vector< char > &ret )
609 {
610  int ini = ret.size();
611  ret.resize( ret.size()+strlen( c ) );
612  while (*c)
613  ret[ini++] = *(c++);
614 }
615 
616 static inline void PushBackString( const string &input, vector< char > &ret )
617 {
618  PushBackUInt( input.length(), ret );
619  PushBackChars( " ", ret );
620  PushBackChars( input.c_str(), ret );
621 }
622 
623 void SaveGame::WriteMissionStringData( std::vector< char > &ret )
624 {
625  RemoveEmpty< MissionStringDat::MSD > ( missionstringdata->m );
626  PushBackUInt( missionstringdata->m.size(), ret );
627  for (MissionStringDat::MSD::iterator i = missionstringdata->m.begin(); i != missionstringdata->m.end(); i++) {
628  const string &key = (*i).first;
629  unsigned int siz = (*i).second.size();
630  if (key == "mission_descriptions" || key == "mission_scripts" || key == "mission_vars" || key == "mission_names") {
631  //*** BLACKLIST ***
632  //Don't bother to write these out since they waste a lot of space and aren't used.
633  siz = 0; //Not writing them out altogether will cause saved games to break.
634  }
635  PushBackChars( "\n", ret );
636  PushBackString( key, ret );
637  PushBackUInt( siz, ret );
638  PushBackChars( " ", ret );
639  for (unsigned int j = 0; j < siz; j++)
640  PushBackString( (*i).second[j], ret );
641  }
642 }
643 
644 void SaveGame::ReadStardate( char* &buf )
645 {
646  string stardate( AnyStringScanInString( buf ) );
647  cout<<"Read stardate: "<<stardate<<endl;
648  _Universe->current_stardate.InitTrek( stardate );
649 }
650 
651 void SaveGame::ReadSavedPackets( char* &buf,
652  bool commitfactions,
653  bool skip_news,
654  bool select_data,
655  const std::set< std::string > &select_data_filter )
656 {
657  int a = 0;
658  char unitname[1024];
659  char factname[1024];
660  while ( 3 == sscanf( buf, "%d %s %s", &a, unitname, factname ) ) {
661  //Put i to point after what we parsed (on the 3rd space read)
662  while ( (*buf) && isspace( *buf ) )
663  ++buf;
664  buf += hopto( buf, ' ', '\n', 0 );
665  buf += hopto( buf, ' ', '\n', 0 );
666  buf += hopto( buf, ' ', '\n', 0 );
667  if ( a == 0 && 0 == strcmp( unitname, "factions" ) && 0 == strcmp( factname, "begin" ) ) {
668  if (commitfactions) FactionUtil::LoadSerializedFaction( buf );
669  break; //GOT TO BE THE LAST>... cus it's stupid :-) and mac requires the factions to be loaded AFTER this function call
670  } else if ( a == 0 && 0 == strcmp( unitname, "mission" ) && 0 == strcmp( factname, "data" ) ) {
671  ReadMissionData( buf, select_data, select_data_filter );
672  } else if ( a == 0 && 0 == strcmp( unitname, "missionstring" ) && 0 == strcmp( factname, "data" ) ) {
673  ReadMissionStringData( buf, select_data, select_data_filter );
674  } else if ( a == 0 && 0 == strcmp( unitname, "python" ) && 0 == strcmp( factname, "data" ) ) {
675  last_written_pickled_data = last_pickled_data = UnpickleAllMissions( buf );
676  } else if ( a == 0 && 0 == strcmp( unitname, "news" ) && 0 == strcmp( factname, "data" ) ) {
677  if (commitfactions) ReadNewsData( buf, skip_news );
678  } else if ( a == 0 && 0 == strcmp( unitname, "stardate" ) && 0 == strcmp( factname, "data" ) ) {
679  //On server side we expect the latest saved stardate in dynaverse.dat too
680  if (commitfactions && !SERVER /*server never wants to take "orders" from shapeshifters...*/)
681  ReadStardate( buf );
682  else
683  AnyStringScanInString( buf );
684  } else {
685  char output[31] = {0};
686  strncpy( output, buf, 30 );
687  printf( "buf unrecognized %s...\n", output );
688  }
689  }
690 }
691 
693 {
694  unsigned int i;
695  vector< string >scripts = getMissionStringData( "active_scripts" );
696  vector< string >missions = getMissionStringData( "active_missions" );
697  PyRun_SimpleString(
698  "import VS\nVS.loading_active_missions=True\nprint \"Loading active missions \"+str(VS.loading_active_missions)\n" );
699  //kill any leftovers so they don't get loaded twice.
700  Mission *ignoreMission = Mission::getNthPlayerMission( _Universe->CurrentCockpit(), 0 );
701  for (i = active_missions.size()-1; i > 0; --i) //don't terminate zeroth mission
702  if (active_missions[i]->player_num == _Universe->CurrentCockpit()
703  && active_missions[i] != ignoreMission)
705  for (i = 0; i < scripts.size() && i < missions.size(); ++i) {
706  try {
707  if ( !missions[i].empty() ) //Built-in/networking missions
708  LoadMission( missions[i].c_str(), scripts[i], false );
709  }
710  catch (...) {
711  if ( PyErr_Occurred() ) {
712  PyErr_Print();
713  PyErr_Clear();
714  fflush( stderr );
715  fflush( stdout );
716  } else {throw; }}
717  }
718  PyRun_SimpleString( "import VS\nVS.loading_active_missions=False\n" );
719  getMissionStringData( "active_scripts" ) = scripts;
720  getMissionStringData( "active_missions" ) = missions;
721 }
722 
724 {
725  return string( "\n" )+XMLSupport::tostring( su->type )+string( " " )+su->filename+" "+su->faction;
726 }
727 
728 extern bool STATIC_VARS_DESTROYED;
729 
730 static char * tmprealloc( char *var, int &oldlength, int newlength )
731 {
732  if (oldlength < newlength) {
733  oldlength = newlength;
734  var = (char*) realloc( var, newlength );
735  }
736  memset( var, 0, newlength );
737  return var;
738 }
739 
740 string SaveGame::WritePlayerData( const QVector &FP,
741  std::vector< std::string >unitname,
742  const char *systemname,
743  float credits,
744  std::string fact )
745 {
746  string playerdata( "" );
747  int MB = MAXBUFFER;
748  char *tmp = (char*) malloc( MB );
749  memset( tmp, 0, MB );
750 
751  QVector FighterPos = PlayerLocation-FP;
752  FighterPos = FP;
753  string pipedunitname = createPipedString( unitname );
754  tmp = tmprealloc( tmp, MB, pipedunitname.length()+strlen( systemname )+256 /*4 floats*/ );
755  //If we specify no faction, it won't be saved in there
756  if (fact != "")
757  sprintf( tmp, "%s^%f^%s %f %f %f %s", systemname, credits,
758  pipedunitname.c_str(), FighterPos.i, FighterPos.j, FighterPos.k, fact.c_str() );
759  else
760  sprintf( tmp, "%s^%f^%s %f %f %f", systemname, credits, pipedunitname.c_str(), FighterPos.i, FighterPos.j, FighterPos.k );
761  playerdata = string( tmp );
762  this->playerfaction = fact;
763  SetSavedCredits( credits );
764  free( tmp );
765  tmp = NULL;
766 
767  return playerdata;
768 }
769 
771 {
772  string dyn_univ( "" );
773  int MB = MAXBUFFER;
774  char *tmp = (char*) malloc( MB );
775  memset( tmp, 0, MB );
776  //Write mission data
777  //we save the stardate
778  if (SERVER) {
779  cerr<<"SAVING STARDATE - SERVER="<<SERVER<<endl;
780  }
782  dyn_univ += "\n0 stardate data " + stardate;
783 
784  memset( tmp, 0, MB );
785  sprintf( tmp, "\n%d %s %s", 0, "mission", "data " );
786  dyn_univ += string( tmp );
787  dyn_univ += WriteMissionData();
788  memset( tmp, 0, MB );
789  sprintf( tmp, "\n%d %s %s", 0, "missionstring", "data " );
790  dyn_univ += string( tmp );
791  vector< char >missionstringdata1;
792  WriteMissionStringData( missionstringdata1 );
793  dyn_univ += string( &missionstringdata1[0], missionstringdata1.size() );
795  last_written_pickled_data = PickleAllMissions();
796  tmp = tmprealloc( tmp, MB, last_written_pickled_data.length()+256 /*4 floats*/ );
797  sprintf( tmp, "\n%d %s %s %s ", 0, "python", "data", last_written_pickled_data.c_str() );
798  dyn_univ += string( tmp );
799 
800  //Write news data
801  memset( tmp, 0, MB );
802  sprintf( tmp, "\n%d %s %s", 0, "news", "data " );
803  dyn_univ += string( tmp );
804  dyn_univ += WriteNewsData();
805  //Write faction relationships
806  memset( tmp, 0, MB );
807  sprintf( tmp, "\n%d %s %s", 0, "factions", "begin " );
808  dyn_univ += string( tmp );
809  dyn_univ += FactionUtil::SerializeFaction();
810 
811  free( tmp );
812  tmp = NULL;
813 
814  return dyn_univ;
815 }
816 
817 using namespace VSFileSystem;
818 
820  const QVector &FP,
821  float credits,
822  std::vector< std::string >unitname,
823  int player_num,
824  std::string fact,
825  bool write )
826 {
827  savestring = string( "" );
828  printf( "Writing Save Game %s", outputsavegame.c_str() );
829  savestring += WritePlayerData( FP, unitname, systemname, credits, fact );
830  savestring += WriteDynamicUniverse();
831  if (outputsavegame.length() != 0) {
832  if (write) {
833  VSFile f;
834  VSError err = f.OpenCreateWrite( outputsavegame, SaveFile );
835  if (err <= Ok) {
836  //check
837  //WRITE THE SAVEGAME TO THE MISSION SAVENAME
838  f.Write( savestring.c_str(), savestring.length() );
839  f.Close();
840  if (player_num != -1) {
841  //AND THEN COPY IT TO THE SPECIFIED SAVENAME (from save.4.x.txt)
842  last_pickled_data = last_written_pickled_data;
843  string sg = GetWritePlayerSaveGame( player_num );
844  SaveFileCopy( outputsavegame.c_str(), sg.c_str() );
845  }
846  } else {
847  //error occured while opening file
848  cerr<<"occured while opening file: "<<outputsavegame<<endl;
849  }
850  }
851  }
852  return savestring;
853 }
854 
855 static float savedcredits = 0;
857 {
858  return savedcredits;
859 }
860 
862 {
863  savedcredits = c;
864 }
865 
866 void SaveGame::SetOutputFileName( const string &filename )
867 {
868  if ( !filename.empty() )
869  outputsavegame = string( "Autosave-" )+filename;
870  else
871  outputsavegame = string( "Autosave" ); //empty name?
872 }
873 
874 void SaveGame::ParseSaveGame( const string &filename_p,
875  string &FSS,
876  const string &originalstarsystem,
877  QVector &PP,
878  bool &shouldupdatepos,
879  float &credits,
880  vector< string > &savedstarship,
881  int player_num,
882  const string &save_contents,
883  bool read,
884  bool commitfaction,
885  bool quick_read,
886  bool skip_news,
887  bool select_data,
888  const std::set< std::string > &select_data_filter )
889 {
890  const string &str = save_contents; //alias
891  string filename;
892  //Now leave filename empty, use the default name regardless...
893  shouldupdatepos = !(PlayerLocation.i == FLT_MAX || PlayerLocation.j == FLT_MAX || PlayerLocation.k == FLT_MAX);
894  //WE WILL ALWAYS SAVE THE CURRENT SAVEGAME IN THE MISSION SAVENAME (IT WILL BE COPIED TO THE SPECIFIED SAVENAME)
895  SetOutputFileName( filename );
896  VSFile f;
897  VSError err = FileNotFound;
898  if (read) {
899  //TRY TO GET THE SPECIFIED SAVENAME TO LOAD
900  string plsave = GetReadPlayerSaveGame( player_num );
901  if ( plsave.length() ) {
902  err = f.OpenReadOnly( plsave, SaveFile );
903  if (err > Ok) //failed in SaveFile
904  //Try as an UnknownFile to get a datadir saved game, like New_Game.
905  err = f.OpenReadOnly( plsave, UnknownFile );
906  } else if (filename.length() > 0) {
907  //IF NONE SIMPLY LOAD THE MISSION DEFAULT ONE
908  err = f.OpenReadOnly( filename, SaveFile );
909  }
910  }
911  if (err <= Ok) {
912  if (quick_read) {
913  char *buf = (char*) malloc( game_options.quick_savegame_summaries_buffer+1 );
914  buf[game_options.quick_savegame_summaries_buffer] = '\0';
915  err = f.ReadLine( buf, game_options.quick_savegame_summaries_buffer );
916  savestring = buf;
917  free( buf );
918  } else {
919  savestring = f.ReadFull();
920  }
921  }
922  if ( err <= Ok || (!read && str != "") ) {
923  if (!read)
924  savestring = str;
925  if (savestring.length() > 0) {
926  char *buf = new char[savestring.length()+1];
927  buf[savestring.length()] = '\0';
928  memcpy( buf, savestring.c_str(), savestring.length() );
929  int headlen = hopto( buf, '\n', '\n', 0 );
930  char *deletebuf = buf;
931  char *tmp2 = (char*) malloc( headlen+2 );
932  char *freetmp2 = tmp2;
933  char *factionname = (char*) malloc( headlen+2 );
934  if ( headlen > 0 && (buf[headlen-1] == '\n' || buf[headlen-1] == ' ' || buf[headlen-1] == '\r') )
935  buf[headlen-1] = '\0';
936  factionname[headlen+1] = '\0';
937  QVector tmppos;
938  int res = sscanf( buf, "%s %lf %lf %lf %s", tmp2, &tmppos.i, &tmppos.j, &tmppos.k, factionname );
939  if (res == 4 || res == 5) {
940  //Extract credits & starship
941  for (int j = 0; '\0' != tmp2[j]; j++)
942  if (tmp2[j] == '^') {
943  sscanf( tmp2+j+1, "%f", &credits );
944  tmp2[j] = '\0';
945  for (int k = j+1; tmp2[k] != '\0'; k++)
946  if (tmp2[k] == '^') {
947  tmp2[k] = '\0';
948  savedstarship.clear();
949  savedstarship = parsePipedString( tmp2+k+1 );
950  break;
951  }
952  break;
953  }
954  //In networking save we include the faction at the end of the first line
955  if (res == 5) {
956  playerfaction = string( factionname );
957  cout<<"Found faction in save file : "<<playerfaction<<endl;
958  } else {
959  //If no faction -> default to privateer
960  playerfaction = string( "privateer" );
961  cout<<"Faction not found assigning default one: privateer"<<endl;
962  }
963  free( factionname );
964  if (ForceStarSystem.length() == 0)
965  ForceStarSystem = string( tmp2 );
966  if (PlayerLocation.i == FLT_MAX || PlayerLocation.j == FLT_MAX || PlayerLocation.k == FLT_MAX) {
967  shouldupdatepos = true;
968  PlayerLocation = tmppos; //LaunchUnitNear(tmppos);
969  }
970  buf += headlen;
971  ReadSavedPackets( buf, commitfaction, skip_news, select_data, select_data_filter );
972  }
973  free( freetmp2 );
974  freetmp2 = NULL;
975  tmp2 = NULL;
976  delete[] deletebuf;
977  }
978  if (read)
979  f.Close();
980  }
981  if (PlayerLocation.i == FLT_MAX || PlayerLocation.j == FLT_MAX || PlayerLocation.k == FLT_MAX) {
982  shouldupdatepos = false;
983  PlayerLocation = PP;
984  } else {
985  PP = PlayerLocation;
986  shouldupdatepos = true;
987  }
988  if (ForceStarSystem.length() == 0) {
989  ForceStarSystem = FSS;
990  originalsystem = FSS;
991  } else {
992  originalsystem = ForceStarSystem;
993  FSS = ForceStarSystem;
994  }
995  SetSavedCredits( credits );
996 }
997 
998 const string& GetCurrentSaveGame()
999 {
1000  return CurrentSaveGameName;
1001 }
1002 
1003 string SetCurrentSaveGame( string newname )
1004 {
1005  string oldname = CurrentSaveGameName;
1006  CurrentSaveGameName = newname;
1007  return oldname;
1008 }
1009 
1010 const string& GetSaveDir()
1011 {
1012  static string rv = VSFileSystem::homedir+"/save/";
1013  return rv;
1014 }
1015