|
|
|
@ -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)
|
|
|
|
|