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()
if not msvc:
if platform == "Windows":
env.Append(CXXFLAGS=['-std=gnu++98'])
else:
env.Append(CXXFLAGS=['-std=c++98'])
env.Append(CXXFLAGS=['-std=c++11'])
env.Append(CXXFLAGS=['-Wno-invalid-offsetof'])
if platform == "Linux":
env.Append(CXXFLAGS=['-Wno-unused-result'])

View File

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

View File

@ -3,6 +3,7 @@
#include <sstream>
#include <cmath>
#include <climits>
#include <memory>
#include <vector>
#include <set>
#include <bzlib.h>
@ -262,7 +263,15 @@ std::vector<char> GameSave::Serialise()
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)
@ -1935,24 +1944,12 @@ void GameSave::readPSv(char * data, 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 x, y, i, wallDataFound = 0;
int posCount, signsCount;
int x, y, i;
// minimum version this save is compatible with
// when building, this number may be increased depending on what elements are used
// or what properties are detected
int minimumMajorVersion = 90, minimumMinorVersion = 2;
bson b;
std::fill(elementCount, elementCount+PT_NUM, 0);
//Get coords in blocks
blockX = 0;//orig_x0/CELL;
@ -1968,26 +1965,26 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
fullW = blockW*CELL;
fullH = blockH*CELL;
//Copy fan and wall data
wallData = (unsigned char*)malloc(blockW*blockH);
wallDataLen = blockW*blockH;
fanData = (unsigned char*)malloc((blockW*blockH)*2);
fanDataLen = 0;
pressData = (unsigned char*)malloc((blockW*blockH)*2);
vxData = (unsigned char*)malloc((blockW*blockH)*2);
vyData = (unsigned char*)malloc((blockW*blockH)*2);
ambientData = (unsigned char*)malloc((blockW*blockH)*2);
// Copy fan and wall data
auto wallData = std::unique_ptr<unsigned char[]>(new unsigned char[blockWidth*blockHeight]);
bool hasWallData = false;
auto fanData = std::unique_ptr<unsigned char[]>(new unsigned char[blockWidth*blockHeight*2]);
auto pressData = std::unique_ptr<unsigned char[]>(new unsigned char[blockWidth*blockHeight*2]);
auto vxData = std::unique_ptr<unsigned char[]>(new unsigned char[blockWidth*blockHeight*2]);
auto vyData = std::unique_ptr<unsigned char[]>(new unsigned char[blockWidth*blockHeight*2]);
auto ambientData = std::unique_ptr<unsigned char[]>(new unsigned char[blockWidth*blockHeight*2]);
std::fill(&ambientData[0], &ambientData[blockWidth*blockHeight*2], 0);
if (!wallData || !fanData || !pressData || !vxData || !vyData || !ambientData)
{
puts("Save Error, out of memory\n");
outputData = NULL;
goto fin;
}
throw BuildException("Save error, out of memory (blockmaps)");
unsigned int wallDataLen = blockWidth*blockHeight, fanDataLen = 0, pressDataLen = 0, vxDataLen = 0, vyDataLen = 0, ambientDataLen = 0;
for(x = blockX; x < blockX+blockW; x++)
{
for(y = blockY; y < blockY+blockH; y++)
{
wallData[(y-blockY)*blockW+(x-blockX)] = blockMap[y][x];
if (blockMap[y][x])
hasWallData = true;
//save pressure and x/y velocity grids
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 >> 8;
if(blockMap[y][x] && !wallDataFound)
wallDataFound = 1;
if(blockMap[y][x]==WL_FAN)
{
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
//partsPosFirstMap is pmap for the first particle in each position
//partsPosLastMap is pmap for the last particle 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
partsPosFirstMap = (unsigned int *)calloc(fullW*fullH, sizeof(unsigned));
partsPosLastMap = (unsigned int *)calloc(fullW*fullH, sizeof(unsigned));
partsPosCount = (unsigned int *)calloc(fullW*fullH, sizeof(unsigned));
partsPosLink = (unsigned int *)calloc(NPART, sizeof(unsigned));
auto partsPosFirstMap = std::unique_ptr<unsigned[]>(new unsigned[fullW*fullH]);
auto partsPosLastMap = std::unique_ptr<unsigned[]>(new unsigned[fullW*fullH]);
auto partsPosCount = std::unique_ptr<unsigned[]>(new unsigned[fullW*fullH]);
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++)
{
if(particles[i].type)
@ -2067,13 +2059,15 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
}
//Store number of particles in each position
partsPosData = (unsigned char*)malloc(fullW*fullH*3);
partsPosDataLen = 0;
auto partsPosData = std::unique_ptr<unsigned char[]>(new unsigned char[fullW*fullH*3]);
unsigned int partsPosDataLen = 0;
if (!partsPosData)
throw BuildException("Save error, out of memory (partposdata)");
for (y=0;y<fullH;y++)
{
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&0x0000FF00)>>8;
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|
life[2] means a second byte (for a 16 bit field) if life[1] is present
*/
partsData = (unsigned char *)malloc(NPART * (sizeof(Particle)+1));
partsDataLen = 0;
partsSaveIndex = (unsigned int *)calloc(NPART, sizeof(unsigned));
partsCount = 0;
auto partsData = std::unique_ptr<unsigned char[]>(new unsigned char[NPART * (sizeof(Particle)+1)]);
unsigned int partsDataLen = 0;
auto partsSaveIndex = std::unique_ptr<unsigned[]>(new unsigned[NPART]);
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 (x=0;x<fullW;x++)
@ -2111,7 +2108,6 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
//Type (required)
partsData[partsDataLen++] = particles[i].type;
elementCount[particles[i].type]++;
//Location of the field descriptor
fieldDescLoc = partsDataLen++;
@ -2238,6 +2234,9 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
partsData[fieldDescLoc] = fieldDesc;
partsData[fieldDescLoc+1] = fieldDesc>>8;
if (particles[i].type == PT_SOAP)
soapCount++;
if (particles[i].type == PT_RPEL && particles[i].ctype)
{
RESTRICTVERSION(91, 4);
@ -2264,52 +2263,57 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
}
}
soapLinkData = (unsigned char*)malloc(3*elementCount[PT_SOAP]);
soapLinkDataLen = 0;
//Iterate through particles in the same order that they were saved
for (y=0;y<fullH;y++)
unsigned char *soapLinkData = NULL;
auto soapLinkDataPtr = std::unique_ptr<unsigned char[]>();
unsigned int soapLinkDataLen = 0;
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
i = partsPosFirstMap[y*fullW + x];
//Loop while there is a pmap entry
while (i)
for (x=0;x<fullW;x++)
{
//Turn pmap entry into a partsptr index
i = i>>8;
if (particles[i].type==PT_SOAP)
//Find the first particle in this position
i = partsPosFirstMap[y*fullW + x];
//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
//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)
//Turn pmap entry into a partsptr index
i = i>>8;
if (particles[i].type==PT_SOAP)
{
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;
soapLinkData[soapLinkDataLen++] = (linkedIndex&0x0000FF);
//Get the pmap entry for the next particle in the same position
i = partsPosLink[i];
}
//Get the pmap entry for the next particle in the same position
i = partsPosLink[i];
}
}
}
if(!soapLinkDataLen)
{
free(soapLinkData);
soapLinkData = NULL;
}
if(!partsDataLen)
{
free(partsData);
partsData = NULL;
}
bson b;
b.data = 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
std::unique_ptr<bson, decltype(bson_deleter)> b_ptr(&b, bson_deleter);
bson_init(&b);
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, "rightSelectedElement", sr);
//bson_append_int(&b, "activeMenu", active_menu);
if (partsData)
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())
if (partsData && partsDataLen)
{
bson_append_start_array(&b, "palette");
for(std::vector<PaletteItem>::iterator iter = palette.begin(), end = palette.end(); iter != end; ++iter)
bson_append_binary(&b, "parts", BSON_BIN_USER, (const char *)partsData.get(), partsDataLen);
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++)
{
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);
}
if (bson_finish(&b) == BSON_ERROR)
goto fin;
throw BuildException("Error building bson data");
finalData = (unsigned char *)bson_data(&b);
finalDataLen = bson_size(&b);
outputDataLen = finalDataLen*2+12;
outputData = new unsigned char[outputDataLen];
unsigned char *finalData = (unsigned char*)bson_data(&b);
unsigned int finalDataLen = bson_size(&b);
auto outputData = std::unique_ptr<unsigned char[]>(new unsigned char[finalDataLen*2+12]);
if (!outputData)
throw BuildException("Save error, out of memory (finalData): " + format::NumberToString<unsigned int>(finalDataLen*2+12));
outputData[0] = 'O';
outputData[1] = 'P';
@ -2419,39 +2428,20 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
outputData[10] = finalDataLen >> 16;
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");
delete [] outputData;
dataLength = 0;
outputData = NULL;
goto fin;
throw BuildException("Save error, could not compress (ret " + format::NumberToString<int>(bz2ret) + ")");
}
#ifdef DEBUG
printf("compressed data: %d\n", outputDataLen);
printf("compressed data: %d\n", compressedSize);
#endif
dataLength = outputDataLen + 12;
dataLength = compressedSize + 12;
fin:
bson_destroy(&b);
free(partsData);
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;
char *saveData = new char[dataLength];
std::copy(&outputData[0], &outputData[dataLength], &saveData[0]);
return saveData;
}
void GameSave::ConvertBsonToJson(bson_iterator *iter, Json::Value *j, int depth)

View File

@ -26,6 +26,17 @@ public:
~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
{
public:

View File

@ -1241,7 +1241,7 @@ void GameController::OpenLocalSaveWindow(bool asCurrent)
std::vector<char> saveData = gameSave->Serialise();
if (saveData.size() == 0)
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.");
else
gameModel->SetInfoTip("Saved Successfully");

View File

@ -121,7 +121,7 @@ void LocalSaveActivity::saveWrite(std::string finalFilename)
std::vector<char> saveData = gameSave->Serialise();
if (saveData.size() == 0)
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.");
else
{