330 lines
7.9 KiB
C++
330 lines
7.9 KiB
C++
#include "save_load.h"
|
|
#include "util/save_file.h"
|
|
#include "references.h"
|
|
#include "logging.h"
|
|
#include "obj/universe.h"
|
|
#include "obj/obj_group.h"
|
|
#include "empire.h"
|
|
#include "physics/physics_world.h"
|
|
#include "design/projectiles.h"
|
|
#include "main/tick.h"
|
|
#include "design/hull.h"
|
|
#include "design/subsystem.h"
|
|
#include "design/effector.h"
|
|
#include "main/initialization.h"
|
|
#include <map>
|
|
#include <assert.h>
|
|
|
|
extern std::map<int,ObjectGroup*> groups;
|
|
extern int SAVE_VERSION, START_VERSION;
|
|
|
|
void addSubsystemIdentifiers(SaveFile& file) {
|
|
unsigned cnt = getSubsystemDefCount();
|
|
for(unsigned i = 0; i < cnt; ++i) {
|
|
const SubsystemDef* def = getSubsystemDef(i);
|
|
file.addIdentifier(SI_Subsystem, def->index, def->id);
|
|
|
|
for(unsigned j = 0, jcnt = def->modules.size(); j < jcnt; ++j) {
|
|
auto* mod = def->modules[j];
|
|
file.addIdentifier(SI_SubsystemModule, mod->umodid, mod->umodident);
|
|
}
|
|
|
|
foreach(it, def->modifierIds) {
|
|
auto* mod = it->second;
|
|
file.addIdentifier(SI_SubsystemModifier, mod->umodifid, def->id+"::"+it->first);
|
|
}
|
|
}
|
|
|
|
for(auto it = shipVariableIndices.begin(), end = shipVariableIndices.end(); it != end; ++it)
|
|
file.addIdentifier(SI_ShipVar, it->second, it->first);
|
|
|
|
for(auto it = variableIndices.begin(), end = variableIndices.end(); it != end; ++it)
|
|
file.addIdentifier(SI_SubsystemVar, it->second, it->first);
|
|
|
|
for(auto it = hexVariableIndices.begin(), end = hexVariableIndices.end(); it != end; ++it)
|
|
file.addIdentifier(SI_HexVar, it->second, it->first);
|
|
|
|
for(auto it = variableIndices.begin(), end = variableIndices.end(); it != end; ++it)
|
|
file.addIdentifier(SI_SubsystemVar, it->second, it->first);
|
|
|
|
for(size_t i = 0, cnt = getEffectorDefinitionCount(); i < cnt; ++i) {
|
|
auto* effdef = getEffectorDefinition(i);
|
|
file.addIdentifier(SI_Effector, effdef->index, effdef->name);
|
|
}
|
|
|
|
for(size_t i = 0, cnt = getEffectDefinitionCount(); i < cnt; ++i) {
|
|
auto* effdef = getEffectDefinition(i);
|
|
file.addIdentifier(SI_Effect, effdef->id, effdef->name);
|
|
}
|
|
}
|
|
|
|
void addHullIdentifiers(SaveFile& file) {
|
|
unsigned cnt = getHullCount();
|
|
for(unsigned i = 0; i < cnt; ++i) {
|
|
const HullDef* hull = getHullDefinition(i);
|
|
file.addIdentifier(SI_Hull, hull->id, hull->ident);
|
|
}
|
|
}
|
|
|
|
void addShipsetIdentifiers(SaveFile& file) {
|
|
unsigned cnt = getShipsetCount();
|
|
for(unsigned i = 0; i < cnt; ++i) {
|
|
auto* set = getShipset(i);
|
|
file.addIdentifier(SI_Shipset, set->id, set->ident);
|
|
}
|
|
}
|
|
|
|
void addDummyIdentifiers(SaveFile& file) {
|
|
if(file < SFV_0007) {
|
|
unsigned i = 0;
|
|
file.addDummyLoadIdentifier(SI_Effector, i++, "CarpetBomb");
|
|
file.addDummyLoadIdentifier(SI_Effector, i++, "Railgun");
|
|
file.addDummyLoadIdentifier(SI_Effector, i++, "Laser");
|
|
file.addDummyLoadIdentifier(SI_Effector, i++, "PurpleLaser");
|
|
file.addDummyLoadIdentifier(SI_Effector, i++, "Rockets");
|
|
file.addDummyLoadIdentifier(SI_Effector, i++, "Missile");
|
|
file.addDummyLoadIdentifier(SI_Effector, i++, "Torpedo");
|
|
file.addDummyLoadIdentifier(SI_Effector, i++, "PopulationBomb");
|
|
file.addDummyLoadIdentifier(SI_Effector, i++, "WaveBeam");
|
|
file.addDummyLoadIdentifier(SI_Effector, i++, "StationArtillery");
|
|
}
|
|
}
|
|
|
|
bool saveGame(const std::string& filename) {
|
|
//TODO: Handle errors gracefully, or guarantee they cannot occur
|
|
try {
|
|
SaveFile* pfile = SaveFile::open(filename, SM_Write);
|
|
SaveFile& file = *pfile;
|
|
if(&file == 0) {
|
|
error("Unable to open file '%s'", filename.c_str());
|
|
return false;
|
|
}
|
|
|
|
addSubsystemIdentifiers(file);
|
|
addHullIdentifiers(file);
|
|
addShipsetIdentifiers(file);
|
|
|
|
devices.scripts.server->saveIdentifiers(file);
|
|
|
|
file.saveIdentifiers();
|
|
file << file.scriptVersion;
|
|
file << file.startVersion;
|
|
file << (unsigned)devices.mods.activeMods.size();
|
|
foreach(it, devices.mods.activeMods) {
|
|
file << (*it)->ident;
|
|
file << (*it)->version;
|
|
}
|
|
|
|
file.boundary();
|
|
|
|
saveGameConfig(file);
|
|
|
|
file.boundary();
|
|
|
|
file << devices.driver->getGameTime();
|
|
|
|
Empire::saveEmpires(file);
|
|
|
|
file.boundary();
|
|
|
|
saveEffectors(file);
|
|
|
|
file.boundary();
|
|
|
|
//Save physics
|
|
if(devices.physics) {
|
|
file << true;
|
|
devices.physics->writeSetup(file);
|
|
}
|
|
else {
|
|
file << false;
|
|
}
|
|
|
|
if(devices.nodePhysics) {
|
|
file << true;
|
|
devices.nodePhysics->writeSetup(file);
|
|
}
|
|
else {
|
|
file << false;
|
|
}
|
|
|
|
file.boundary();
|
|
|
|
//Save object id sequences
|
|
unsigned typeCount = getScriptObjectTypeCount();
|
|
file << typeCount;
|
|
for(unsigned i = 0; i < typeCount; ++i) {
|
|
auto* type = getScriptObjectType(i);
|
|
file << type->nextID.get();
|
|
}
|
|
|
|
file.boundary();
|
|
|
|
//Save object groups
|
|
unsigned groupCount = (unsigned)groups.size();
|
|
file << groupCount;
|
|
for(auto i = groups.begin(), end = groups.end(); i != end; ++i)
|
|
i->second->save(file);
|
|
|
|
file.boundary();
|
|
|
|
//Save objects
|
|
unsigned objectCount = (unsigned)devices.universe->children.size();
|
|
file << objectCount;
|
|
|
|
for(unsigned i = 0; i < objectCount; ++i)
|
|
devices.universe->children[i]->save(file);
|
|
|
|
file.boundary();
|
|
|
|
saveProjectiles(file);
|
|
|
|
file.boundary();
|
|
|
|
devices.scripts.server->save(file);
|
|
|
|
if(devices.scripts.client)
|
|
devices.scripts.client->save(file);
|
|
else
|
|
file << "";
|
|
|
|
file.close();
|
|
return true;
|
|
}
|
|
catch(SaveFileError& err) {
|
|
error("Failed to save: %s", err.text);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool loadGame(const std::string& filename) {
|
|
#ifndef _DEBUG
|
|
try {
|
|
#endif
|
|
SaveFile& file = *SaveFile::open(filename, SM_Read);
|
|
if(&file == 0) {
|
|
error("Unable to open file '%s'", filename.c_str());
|
|
return false;
|
|
}
|
|
|
|
file.loadIdentifiers();
|
|
addDummyIdentifiers(file);
|
|
|
|
SaveFileInfo info;
|
|
readSaveFileInfo(file, info);
|
|
file.scriptVersion = info.version;
|
|
file.startVersion = info.startVersion;
|
|
SAVE_VERSION = file.scriptVersion;
|
|
START_VERSION = file.startVersion;
|
|
|
|
//Initialize server scripts
|
|
devices.scripts.server->init();
|
|
|
|
//Load identifiers
|
|
addSubsystemIdentifiers(file);
|
|
addHullIdentifiers(file);
|
|
addShipsetIdentifiers(file);
|
|
|
|
devices.scripts.server->saveIdentifiers(file);
|
|
file.scriptVersion = info.version;
|
|
file.startVersion = info.startVersion;
|
|
|
|
file.finalizeIdentifiers();
|
|
|
|
file.boundary();
|
|
|
|
loadGameConfig(file);
|
|
file.boundary();
|
|
|
|
devices.driver->resetGameTime(file);
|
|
resetGameTime();
|
|
|
|
Empire::loadEmpires(file);
|
|
|
|
file.boundary();
|
|
|
|
loadEffectors(file);
|
|
|
|
file.boundary();
|
|
|
|
//Load physics
|
|
if(file.read<bool>())
|
|
devices.physics = PhysicsWorld::fromSave(file);
|
|
if(file.read<bool>())
|
|
devices.nodePhysics = PhysicsWorld::fromSave(file);
|
|
|
|
file.boundary();
|
|
|
|
//Load object id sequences
|
|
unsigned typeCount = file;
|
|
for(unsigned i = 0; i < typeCount; ++i) {
|
|
auto* type = getScriptObjectType(i);
|
|
type->nextID = file.read<int>();
|
|
}
|
|
|
|
file.boundary();
|
|
|
|
//Load object groups
|
|
unsigned groupCount = file;
|
|
for(unsigned i = 0; i < groupCount; ++i)
|
|
new ObjectGroup(file);
|
|
|
|
file.boundary();
|
|
|
|
//Load objects
|
|
unsigned objectCount = file;
|
|
for(unsigned i = 0; i < objectCount; ++i) {
|
|
Object* obj = file;
|
|
obj->load(file);
|
|
devices.universe->children.push_back( obj ); obj->grab();
|
|
}
|
|
|
|
file.boundary();
|
|
|
|
//Perform post init for groups
|
|
for(auto i = groups.begin(), end = groups.end(); i != end;) {
|
|
ObjectGroup* group = i->second;
|
|
if(group->postLoad()) {
|
|
group->postInit();
|
|
++i;
|
|
}
|
|
else {
|
|
i = groups.erase(i);
|
|
group->drop();
|
|
}
|
|
}
|
|
|
|
loadProjectiles(file);
|
|
|
|
file.boundary();
|
|
|
|
devices.scripts.server->load(file);
|
|
|
|
//Objects that weren't loaded yet at this point are not valid
|
|
invalidateUninitializedObjects();
|
|
|
|
//Perform post load on objects
|
|
for(unsigned i = 0; i < objectCount; ++i)
|
|
devices.universe->children[i]->postLoad();
|
|
|
|
//Post load on effectors
|
|
postLoadEffectors();
|
|
|
|
//Initialize client scripts
|
|
devices.scripts.client->init();
|
|
|
|
//TODO: If we don't have a client, there could still be data to load (if we load it last, we don't have to care)
|
|
if(devices.scripts.client)
|
|
devices.scripts.client->load(file);
|
|
|
|
file.close();
|
|
return true;
|
|
#ifndef _DEBUG
|
|
}
|
|
catch(SaveFileError& err) {
|
|
error("Failed to load save '%s':\n %s", filename.c_str(), err.text);
|
|
return false;
|
|
}
|
|
#endif
|
|
}
|