use c++11, use unique_ptr in GameSave::SerializeOPS

This commit is contained in:
jacob1 2017-12-27 11:50:09 -05:00
parent 23c68b1db1
commit 887d60628d
6 changed files with 150 additions and 151 deletions

View File

@ -396,10 +396,7 @@ elif not GetOption('help'):
env = conf.Finish() env = conf.Finish()
if not msvc: if not msvc:
if platform == "Windows": env.Append(CXXFLAGS=['-std=c++11'])
env.Append(CXXFLAGS=['-std=gnu++98'])
else:
env.Append(CXXFLAGS=['-std=c++98'])
env.Append(CXXFLAGS=['-Wno-invalid-offsetof']) env.Append(CXXFLAGS=['-Wno-invalid-offsetof'])
if platform == "Linux": if platform == "Linux":
env.Append(CXXFLAGS=['-Wno-unused-result']) env.Append(CXXFLAGS=['-Wno-unused-result'])

View File

@ -664,7 +664,8 @@ int bson_finish( bson *b ) {
} }
void bson_destroy( bson *b ) { void bson_destroy( bson *b ) {
bson_free( b->data ); if (b->data)
bson_free( b->data );
b->err = 0; b->err = 0;
b->data = 0; b->data = 0;
b->cur = 0; b->cur = 0;

View File

@ -3,6 +3,7 @@
#include <sstream> #include <sstream>
#include <cmath> #include <cmath>
#include <climits> #include <climits>
#include <memory>
#include <vector> #include <vector>
#include <set> #include <set>
#include <bzlib.h> #include <bzlib.h>
@ -262,7 +263,15 @@ std::vector<char> GameSave::Serialise()
char * GameSave::Serialise(unsigned int & dataSize) char * GameSave::Serialise(unsigned int & dataSize)
{ {
return serialiseOPS(dataSize); try
{
return serialiseOPS(dataSize);
}
catch (BuildException e)
{
std::cout << e.what() << std::endl;
return NULL;
}
} }
vector2d GameSave::Translate(vector2d translate) vector2d GameSave::Translate(vector2d translate)
@ -1935,24 +1944,12 @@ void GameSave::readPSv(char * data, int dataLength)
char * GameSave::serialiseOPS(unsigned int & dataLength) char * GameSave::serialiseOPS(unsigned int & dataLength)
{ {
//Particle *particles = sim->parts;
unsigned char *partsData = NULL, *partsPosData = NULL, *fanData = NULL, *wallData = NULL, *finalData = NULL, *outputData = NULL, *soapLinkData = NULL;
unsigned char *pressData = NULL, *vxData = NULL, *vyData = NULL, *ambientData = NULL;
unsigned *partsPosLink = NULL, *partsPosFirstMap = NULL, *partsPosCount = NULL, *partsPosLastMap = NULL;
unsigned partsCount = 0, *partsSaveIndex = NULL;
unsigned *elementCount = new unsigned[PT_NUM];
unsigned int partsDataLen, partsPosDataLen, fanDataLen, wallDataLen,finalDataLen, outputDataLen, soapLinkDataLen;
unsigned int pressDataLen = 0, vxDataLen = 0, vyDataLen = 0, ambientDataLen = 0;
int blockX, blockY, blockW, blockH, fullX, fullY, fullW, fullH; int blockX, blockY, blockW, blockH, fullX, fullY, fullW, fullH;
int x, y, i, wallDataFound = 0; int x, y, i;
int posCount, signsCount;
// minimum version this save is compatible with // minimum version this save is compatible with
// when building, this number may be increased depending on what elements are used // when building, this number may be increased depending on what elements are used
// or what properties are detected // or what properties are detected
int minimumMajorVersion = 90, minimumMinorVersion = 2; int minimumMajorVersion = 90, minimumMinorVersion = 2;
bson b;
std::fill(elementCount, elementCount+PT_NUM, 0);
//Get coords in blocks //Get coords in blocks
blockX = 0;//orig_x0/CELL; blockX = 0;//orig_x0/CELL;
@ -1968,26 +1965,26 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
fullW = blockW*CELL; fullW = blockW*CELL;
fullH = blockH*CELL; fullH = blockH*CELL;
//Copy fan and wall data // Copy fan and wall data
wallData = (unsigned char*)malloc(blockW*blockH); auto wallData = std::unique_ptr<unsigned char[]>(new unsigned char[blockWidth*blockHeight]);
wallDataLen = blockW*blockH; bool hasWallData = false;
fanData = (unsigned char*)malloc((blockW*blockH)*2); auto fanData = std::unique_ptr<unsigned char[]>(new unsigned char[blockWidth*blockHeight*2]);
fanDataLen = 0; auto pressData = std::unique_ptr<unsigned char[]>(new unsigned char[blockWidth*blockHeight*2]);
pressData = (unsigned char*)malloc((blockW*blockH)*2); auto vxData = std::unique_ptr<unsigned char[]>(new unsigned char[blockWidth*blockHeight*2]);
vxData = (unsigned char*)malloc((blockW*blockH)*2); auto vyData = std::unique_ptr<unsigned char[]>(new unsigned char[blockWidth*blockHeight*2]);
vyData = (unsigned char*)malloc((blockW*blockH)*2); auto ambientData = std::unique_ptr<unsigned char[]>(new unsigned char[blockWidth*blockHeight*2]);
ambientData = (unsigned char*)malloc((blockW*blockH)*2); std::fill(&ambientData[0], &ambientData[blockWidth*blockHeight*2], 0);
if (!wallData || !fanData || !pressData || !vxData || !vyData || !ambientData) if (!wallData || !fanData || !pressData || !vxData || !vyData || !ambientData)
{ throw BuildException("Save error, out of memory (blockmaps)");
puts("Save Error, out of memory\n"); unsigned int wallDataLen = blockWidth*blockHeight, fanDataLen = 0, pressDataLen = 0, vxDataLen = 0, vyDataLen = 0, ambientDataLen = 0;
outputData = NULL;
goto fin;
}
for(x = blockX; x < blockX+blockW; x++) for(x = blockX; x < blockX+blockW; x++)
{ {
for(y = blockY; y < blockY+blockH; y++) for(y = blockY; y < blockY+blockH; y++)
{ {
wallData[(y-blockY)*blockW+(x-blockX)] = blockMap[y][x]; wallData[(y-blockY)*blockW+(x-blockX)] = blockMap[y][x];
if (blockMap[y][x])
hasWallData = true;
//save pressure and x/y velocity grids //save pressure and x/y velocity grids
float pres = std::max(-255.0f,std::min(255.0f,pressure[y][x]))+256.0f; float pres = std::max(-255.0f,std::min(255.0f,pressure[y][x]))+256.0f;
@ -2006,8 +2003,6 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
ambientData[ambientDataLen++] = tempTemp; ambientData[ambientDataLen++] = tempTemp;
ambientData[ambientDataLen++] = tempTemp >> 8; ambientData[ambientDataLen++] = tempTemp >> 8;
if(blockMap[y][x] && !wallDataFound)
wallDataFound = 1;
if(blockMap[y][x]==WL_FAN) if(blockMap[y][x]==WL_FAN)
{ {
i = (int)(fanVelX[y][x]*64.0f+127.5f); i = (int)(fanVelX[y][x]*64.0f+127.5f);
@ -2021,26 +2016,23 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
} }
} }
} }
if(!fanDataLen)
{
free(fanData);
fanData = NULL;
}
if(!wallDataFound)
{
free(wallData);
wallData = NULL;
}
//Index positions of all particles, using linked lists //Index positions of all particles, using linked lists
//partsPosFirstMap is pmap for the first particle in each position //partsPosFirstMap is pmap for the first particle in each position
//partsPosLastMap is pmap for the last particle in each position //partsPosLastMap is pmap for the last particle in each position
//partsPosCount is the number of particles in each position //partsPosCount is the number of particles in each position
//partsPosLink contains, for each particle, (i<<8)|1 of the next particle in the same position //partsPosLink contains, for each particle, (i<<8)|1 of the next particle in the same position
partsPosFirstMap = (unsigned int *)calloc(fullW*fullH, sizeof(unsigned)); auto partsPosFirstMap = std::unique_ptr<unsigned[]>(new unsigned[fullW*fullH]);
partsPosLastMap = (unsigned int *)calloc(fullW*fullH, sizeof(unsigned)); auto partsPosLastMap = std::unique_ptr<unsigned[]>(new unsigned[fullW*fullH]);
partsPosCount = (unsigned int *)calloc(fullW*fullH, sizeof(unsigned)); auto partsPosCount = std::unique_ptr<unsigned[]>(new unsigned[fullW*fullH]);
partsPosLink = (unsigned int *)calloc(NPART, sizeof(unsigned)); auto partsPosLink = std::unique_ptr<unsigned[]>(new unsigned[NPART]);
if (!partsPosFirstMap || !partsPosLastMap || !partsPosCount || !partsPosLink)
throw BuildException("Save error, out of memory (partmaps)");
std::fill(&partsPosFirstMap[0], &partsPosFirstMap[fullW*fullH], 0);
std::fill(&partsPosLastMap[0], &partsPosLastMap[fullW*fullH], 0);
std::fill(&partsPosCount[0], &partsPosCount[fullW*fullH], 0);
std::fill(&partsPosLink[0], &partsPosLink[NPART], 0);
unsigned int soapCount = 0;
for(i = 0; i < particlesCount; i++) for(i = 0; i < particlesCount; i++)
{ {
if(particles[i].type) if(particles[i].type)
@ -2067,13 +2059,15 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
} }
//Store number of particles in each position //Store number of particles in each position
partsPosData = (unsigned char*)malloc(fullW*fullH*3); auto partsPosData = std::unique_ptr<unsigned char[]>(new unsigned char[fullW*fullH*3]);
partsPosDataLen = 0; unsigned int partsPosDataLen = 0;
if (!partsPosData)
throw BuildException("Save error, out of memory (partposdata)");
for (y=0;y<fullH;y++) for (y=0;y<fullH;y++)
{ {
for (x=0;x<fullW;x++) for (x=0;x<fullW;x++)
{ {
posCount = partsPosCount[y*fullW + x]; unsigned int posCount = partsPosCount[y*fullW + x];
partsPosData[partsPosDataLen++] = (posCount&0x00FF0000)>>16; partsPosData[partsPosDataLen++] = (posCount&0x00FF0000)>>16;
partsPosData[partsPosDataLen++] = (posCount&0x0000FF00)>>8; partsPosData[partsPosDataLen++] = (posCount&0x0000FF00)>>8;
partsPosData[partsPosDataLen++] = (posCount&0x000000FF); partsPosData[partsPosDataLen++] = (posCount&0x000000FF);
@ -2086,10 +2080,13 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
| pavg | tmp[3+4] | tmp2[2] | tmp2 | ctype[2] | vy | vx | dcololour | ctype[1] | tmp[2] | tmp[1] | life[2] | life[1] | temp dbl len| | pavg | tmp[3+4] | tmp2[2] | tmp2 | ctype[2] | vy | vx | dcololour | ctype[1] | tmp[2] | tmp[1] | life[2] | life[1] | temp dbl len|
life[2] means a second byte (for a 16 bit field) if life[1] is present life[2] means a second byte (for a 16 bit field) if life[1] is present
*/ */
partsData = (unsigned char *)malloc(NPART * (sizeof(Particle)+1)); auto partsData = std::unique_ptr<unsigned char[]>(new unsigned char[NPART * (sizeof(Particle)+1)]);
partsDataLen = 0; unsigned int partsDataLen = 0;
partsSaveIndex = (unsigned int *)calloc(NPART, sizeof(unsigned)); auto partsSaveIndex = std::unique_ptr<unsigned[]>(new unsigned[NPART]);
partsCount = 0; unsigned int partsCount = 0;
if (!partsData || !partsSaveIndex)
throw BuildException("Save error, out of memory (partsdata)");
std::fill(&partsSaveIndex[0], &partsSaveIndex[NPART], 0);
for (y=0;y<fullH;y++) for (y=0;y<fullH;y++)
{ {
for (x=0;x<fullW;x++) for (x=0;x<fullW;x++)
@ -2111,7 +2108,6 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
//Type (required) //Type (required)
partsData[partsDataLen++] = particles[i].type; partsData[partsDataLen++] = particles[i].type;
elementCount[particles[i].type]++;
//Location of the field descriptor //Location of the field descriptor
fieldDescLoc = partsDataLen++; fieldDescLoc = partsDataLen++;
@ -2238,6 +2234,9 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
partsData[fieldDescLoc] = fieldDesc; partsData[fieldDescLoc] = fieldDesc;
partsData[fieldDescLoc+1] = fieldDesc>>8; partsData[fieldDescLoc+1] = fieldDesc>>8;
if (particles[i].type == PT_SOAP)
soapCount++;
if (particles[i].type == PT_RPEL && particles[i].ctype) if (particles[i].type == PT_RPEL && particles[i].ctype)
{ {
RESTRICTVERSION(91, 4); RESTRICTVERSION(91, 4);
@ -2264,52 +2263,57 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
} }
} }
soapLinkData = (unsigned char*)malloc(3*elementCount[PT_SOAP]); unsigned char *soapLinkData = NULL;
soapLinkDataLen = 0; auto soapLinkDataPtr = std::unique_ptr<unsigned char[]>();
//Iterate through particles in the same order that they were saved unsigned int soapLinkDataLen = 0;
for (y=0;y<fullH;y++) if (soapCount)
{ {
for (x=0;x<fullW;x++) soapLinkData = new unsigned char[3*soapCount];
if (!soapLinkData)
throw BuildException("Save error, out of memory (SOAP)");
soapLinkDataPtr = std::move(std::unique_ptr<unsigned char[]>(soapLinkData));
//Iterate through particles in the same order that they were saved
for (y=0;y<fullH;y++)
{ {
//Find the first particle in this position for (x=0;x<fullW;x++)
i = partsPosFirstMap[y*fullW + x];
//Loop while there is a pmap entry
while (i)
{ {
//Turn pmap entry into a partsptr index //Find the first particle in this position
i = i>>8; i = partsPosFirstMap[y*fullW + x];
if (particles[i].type==PT_SOAP) //Loop while there is a pmap entry
while (i)
{ {
//Only save forward link for each particle, back links can be deduced from other forward links //Turn pmap entry into a partsptr index
//linkedIndex is index within saved particles + 1, 0 means not saved or no link i = i>>8;
unsigned linkedIndex = 0; if (particles[i].type==PT_SOAP)
if ((particles[i].ctype&2) && particles[i].tmp>=0 && particles[i].tmp<NPART)
{ {
linkedIndex = partsSaveIndex[particles[i].tmp]; //Only save forward link for each particle, back links can be deduced from other forward links
//linkedIndex is index within saved particles + 1, 0 means not saved or no link
unsigned linkedIndex = 0;
if ((particles[i].ctype&2) && particles[i].tmp>=0 && particles[i].tmp<NPART)
{
linkedIndex = partsSaveIndex[particles[i].tmp];
}
soapLinkData[soapLinkDataLen++] = (linkedIndex&0xFF0000)>>16;
soapLinkData[soapLinkDataLen++] = (linkedIndex&0x00FF00)>>8;
soapLinkData[soapLinkDataLen++] = (linkedIndex&0x0000FF);
} }
soapLinkData[soapLinkDataLen++] = (linkedIndex&0xFF0000)>>16;
soapLinkData[soapLinkDataLen++] = (linkedIndex&0x00FF00)>>8; //Get the pmap entry for the next particle in the same position
soapLinkData[soapLinkDataLen++] = (linkedIndex&0x0000FF); i = partsPosLink[i];
} }
//Get the pmap entry for the next particle in the same position
i = partsPosLink[i];
} }
} }
} }
if(!soapLinkDataLen)
{ bson b;
free(soapLinkData); b.data = NULL;
soapLinkData = NULL; auto bson_deleter = [](bson * b) { bson_destroy(b); };
} // Use unique_ptr with a custom deleter to ensure that bson_destroy is called even when an exception is thrown
if(!partsDataLen) std::unique_ptr<bson, decltype(bson_deleter)> b_ptr(&b, bson_deleter);
{
free(partsData);
partsData = NULL;
}
bson_init(&b); bson_init(&b);
bson_append_start_object(&b, "origin"); bson_append_start_object(&b, "origin");
@ -2340,34 +2344,38 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
//bson_append_int(&b, "leftSelectedElement", sl); //bson_append_int(&b, "leftSelectedElement", sl);
//bson_append_int(&b, "rightSelectedElement", sr); //bson_append_int(&b, "rightSelectedElement", sr);
//bson_append_int(&b, "activeMenu", active_menu); //bson_append_int(&b, "activeMenu", active_menu);
if (partsData) if (partsData && partsDataLen)
bson_append_binary(&b, "parts", BSON_BIN_USER, (const char *)partsData, partsDataLen);
if (partsPosData)
bson_append_binary(&b, "partsPos", BSON_BIN_USER, (const char *)partsPosData, partsPosDataLen);
if (wallData)
bson_append_binary(&b, "wallMap", BSON_BIN_USER, (const char *)wallData, wallDataLen);
if (fanData)
bson_append_binary(&b, "fanMap", BSON_BIN_USER, (const char *)fanData, fanDataLen);
if (pressData)
bson_append_binary(&b, "pressMap", (char)BSON_BIN_USER, (const char*)pressData, pressDataLen);
if (vxData)
bson_append_binary(&b, "vxMap", (char)BSON_BIN_USER, (const char*)vxData, vxDataLen);
if (vyData)
bson_append_binary(&b, "vyMap", (char)BSON_BIN_USER, (const char*)vyData, vyDataLen);
if (ambientData && this->aheatEnable)
bson_append_binary(&b, "ambientMap", (char)BSON_BIN_USER, (const char*)ambientData, ambientDataLen);
if (soapLinkData)
bson_append_binary(&b, "soapLinks", BSON_BIN_USER, (const char *)soapLinkData, soapLinkDataLen);
if (partsData && palette.size())
{ {
bson_append_start_array(&b, "palette"); bson_append_binary(&b, "parts", BSON_BIN_USER, (const char *)partsData.get(), partsDataLen);
for(std::vector<PaletteItem>::iterator iter = palette.begin(), end = palette.end(); iter != end; ++iter)
if (palette.size())
{ {
bson_append_int(&b, (*iter).first.c_str(), (*iter).second); bson_append_start_array(&b, "palette");
for(std::vector<PaletteItem>::iterator iter = palette.begin(), end = palette.end(); iter != end; ++iter)
{
bson_append_int(&b, (*iter).first.c_str(), (*iter).second);
}
bson_append_finish_array(&b);
} }
bson_append_finish_array(&b);
if (partsPosData && partsPosDataLen)
bson_append_binary(&b, "partsPos", BSON_BIN_USER, (const char *)partsPosData.get(), partsPosDataLen);
} }
signsCount = 0; if (wallData && hasWallData)
bson_append_binary(&b, "wallMap", BSON_BIN_USER, (const char *)wallData.get(), wallDataLen);
if (fanData && fanDataLen)
bson_append_binary(&b, "fanMap", BSON_BIN_USER, (const char *)fanData.get(), fanDataLen);
if (pressData && pressDataLen)
bson_append_binary(&b, "pressMap", (char)BSON_BIN_USER, (const char*)pressData.get(), pressDataLen);
if (vxData && vxDataLen)
bson_append_binary(&b, "vxMap", (char)BSON_BIN_USER, (const char*)vxData.get(), vxDataLen);
if (vyData && vyDataLen)
bson_append_binary(&b, "vyMap", (char)BSON_BIN_USER, (const char*)vyData.get(), vyDataLen);
if (ambientData && this->aheatEnable && ambientDataLen)
bson_append_binary(&b, "ambientMap", (char)BSON_BIN_USER, (const char*)ambientData.get(), ambientDataLen);
if (soapLinkData && soapLinkDataLen)
bson_append_binary(&b, "soapLinks", BSON_BIN_USER, (const char *)soapLinkData, soapLinkDataLen);
unsigned int signsCount = 0;
for (size_t i = 0; i < signs.size(); i++) for (size_t i = 0; i < signs.size(); i++)
{ {
if(signs[i].text.length() && signs[i].x>=0 && signs[i].x<=fullW && signs[i].y>=0 && signs[i].y<=fullH) if(signs[i].text.length() && signs[i].x>=0 && signs[i].x<=fullW && signs[i].y>=0 && signs[i].y<=fullH)
@ -2399,12 +2407,13 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
bson_append_finish_object(&b); bson_append_finish_object(&b);
} }
if (bson_finish(&b) == BSON_ERROR) if (bson_finish(&b) == BSON_ERROR)
goto fin; throw BuildException("Error building bson data");
finalData = (unsigned char *)bson_data(&b); unsigned char *finalData = (unsigned char*)bson_data(&b);
finalDataLen = bson_size(&b); unsigned int finalDataLen = bson_size(&b);
outputDataLen = finalDataLen*2+12; auto outputData = std::unique_ptr<unsigned char[]>(new unsigned char[finalDataLen*2+12]);
outputData = new unsigned char[outputDataLen]; if (!outputData)
throw BuildException("Save error, out of memory (finalData): " + format::NumberToString<unsigned int>(finalDataLen*2+12));
outputData[0] = 'O'; outputData[0] = 'O';
outputData[1] = 'P'; outputData[1] = 'P';
@ -2419,39 +2428,20 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
outputData[10] = finalDataLen >> 16; outputData[10] = finalDataLen >> 16;
outputData[11] = finalDataLen >> 24; outputData[11] = finalDataLen >> 24;
if (BZ2_bzBuffToBuffCompress((char*)(outputData+12), &outputDataLen, (char*)finalData, bson_size(&b), 9, 0, 0) != BZ_OK) unsigned int compressedSize = finalDataLen*2, bz2ret;
if ((bz2ret = BZ2_bzBuffToBuffCompress((char*)(outputData.get()+12), &compressedSize, (char*)finalData, bson_size(&b), 9, 0, 0)) != BZ_OK)
{ {
puts("Save Error\n"); throw BuildException("Save error, could not compress (ret " + format::NumberToString<int>(bz2ret) + ")");
delete [] outputData;
dataLength = 0;
outputData = NULL;
goto fin;
} }
#ifdef DEBUG #ifdef DEBUG
printf("compressed data: %d\n", outputDataLen); printf("compressed data: %d\n", compressedSize);
#endif #endif
dataLength = outputDataLen + 12; dataLength = compressedSize + 12;
fin: char *saveData = new char[dataLength];
bson_destroy(&b); std::copy(&outputData[0], &outputData[dataLength], &saveData[0]);
free(partsData); return saveData;
free(wallData);
free(pressData);
free(vxData);
free(vyData);
free(ambientData);
free(fanData);
delete[] elementCount;
free(partsSaveIndex);
free(soapLinkData);
free(partsPosData);
free(partsPosFirstMap);
free(partsPosLastMap);
free(partsPosCount);
free(partsPosLink);
return (char*)outputData;
} }
void GameSave::ConvertBsonToJson(bson_iterator *iter, Json::Value *j, int depth) void GameSave::ConvertBsonToJson(bson_iterator *iter, Json::Value *j, int depth)

View File

@ -26,6 +26,17 @@ public:
~ParseException() throw() {} ~ParseException() throw() {}
}; };
struct BuildException: public std::exception {
std::string message;
public:
BuildException(std::string message_): message(message_) {}
const char * what() const throw()
{
return message.c_str();
}
~BuildException() throw() {}
};
class GameSave class GameSave
{ {
public: public:

View File

@ -1241,7 +1241,7 @@ void GameController::OpenLocalSaveWindow(bool asCurrent)
std::vector<char> saveData = gameSave->Serialise(); std::vector<char> saveData = gameSave->Serialise();
if (saveData.size() == 0) if (saveData.size() == 0)
new ErrorMessage("Error", "Unable to serialize game data."); new ErrorMessage("Error", "Unable to serialize game data.");
else if (Client::Ref().WriteFile(gameSave->Serialise(), gameModel->GetSaveFile()->GetName())) else if (Client::Ref().WriteFile(saveData, gameModel->GetSaveFile()->GetName()))
new ErrorMessage("Error", "Unable to write save file."); new ErrorMessage("Error", "Unable to write save file.");
else else
gameModel->SetInfoTip("Saved Successfully"); gameModel->SetInfoTip("Saved Successfully");

View File

@ -121,7 +121,7 @@ void LocalSaveActivity::saveWrite(std::string finalFilename)
std::vector<char> saveData = gameSave->Serialise(); std::vector<char> saveData = gameSave->Serialise();
if (saveData.size() == 0) if (saveData.size() == 0)
new ErrorMessage("Error", "Unable to serialize game data."); new ErrorMessage("Error", "Unable to serialize game data.");
else if (Client::Ref().WriteFile(gameSave->Serialise(), finalFilename)) else if (Client::Ref().WriteFile(saveData, finalFilename))
new ErrorMessage("Error", "Unable to write save file."); new ErrorMessage("Error", "Unable to write save file.");
else else
{ {