Saving and loading at position, yuse exceptions for parsing saves

This commit is contained in:
Simon Robertshaw
2012-06-06 01:46:13 +01:00
parent 7063587706
commit 8fae7dbade
6 changed files with 85 additions and 59 deletions

View File

@@ -13,7 +13,6 @@
#include "GameSave.h" #include "GameSave.h"
#include "SimulationData.h" #include "SimulationData.h"
GameSave::GameSave(GameSave & save) : GameSave::GameSave(GameSave & save) :
waterEEnabled(save.waterEEnabled), waterEEnabled(save.waterEEnabled),
legacyEnable(save.legacyEnable), legacyEnable(save.legacyEnable),
@@ -38,7 +37,14 @@ GameSave::GameSave(int width, int height)
GameSave::GameSave(char * data, int dataSize) GameSave::GameSave(char * data, int dataSize)
{ {
std::cout << readPSv(data, dataSize) << std::endl; width, height = 0;
blockMap, blockMapPtr, fanVelX, fanVelXPtr, fanVelY, fanVelYPtr, particles = NULL;
try {
readPSv(data, dataSize);
} catch (ParseException& e) {
this->~GameSave(); //Free any allocated memory
throw;
}
} }
void GameSave::setSize(int newWidth, int newHeight) void GameSave::setSize(int newWidth, int newHeight)
@@ -74,12 +80,11 @@ void GameSave::Transform(matrix2d transform, vector2d translate)
} }
GameSave::ParseResult GameSave::readOPS(char * data, int dataLength) void GameSave::readOPS(char * data, int dataLength)
{ {
unsigned char * inputData = (unsigned char *)data, *bsonData = NULL, *partsData = NULL, *partsPosData = NULL, *fanData = NULL, *wallData = NULL; unsigned char * inputData = (unsigned char *)data, *bsonData = NULL, *partsData = NULL, *partsPosData = NULL, *fanData = NULL, *wallData = NULL;
unsigned int inputDataLen = dataLength, bsonDataLen = 0, partsDataLen, partsPosDataLen, fanDataLen, wallDataLen; unsigned int inputDataLen = dataLength, bsonDataLen = 0, partsDataLen, partsPosDataLen, fanDataLen, wallDataLen;
int i, freeIndicesCount, x, y, j; int i, freeIndicesCount, x, y, j;
ParseResult returnCode = OK;
int *freeIndices = NULL; int *freeIndices = NULL;
int blockX, blockY, blockW, blockH, fullX, fullY, fullW, fullH; int blockX, blockY, blockW, blockH, fullX, fullY, fullW, fullH;
bson b; bson b;
@@ -99,24 +104,15 @@ GameSave::ParseResult GameSave::readOPS(char * data, int dataLength)
//From newer version //From newer version
if(inputData[4] > SAVE_VERSION) if(inputData[4] > SAVE_VERSION)
{ throw ParseException(ParseException::WrongVersion, "Save from newer version");
fprintf(stderr, "Save from newer version\n");
return WrongVersion;
}
//Incompatible cell size //Incompatible cell size
if(inputData[5] > CELL) if(inputData[5] > CELL)
{ throw ParseException(ParseException::InvalidDimensions, "Incorrect CELL size");
fprintf(stderr, "Cell size mismatch\n");
return InvalidDimensions;
}
//Too large/off screen //Too large/off screen
if(blockX+blockW > XRES/CELL || blockY+blockH > YRES/CELL) if(blockX+blockW > XRES/CELL || blockY+blockH > YRES/CELL)
{ throw ParseException(ParseException::InvalidDimensions, "Save too large");
fprintf(stderr, "Save too large\n");
return InvalidDimensions;
}
setSize(fullW, fullH); setSize(fullW, fullH);
@@ -127,19 +123,14 @@ GameSave::ParseResult GameSave::readOPS(char * data, int dataLength)
bsonData = (unsigned char*)malloc(bsonDataLen+1); bsonData = (unsigned char*)malloc(bsonDataLen+1);
if(!bsonData) if(!bsonData)
{ throw ParseException(ParseException::InternalError, "Unable to allocate memory");
fprintf(stderr, "Internal error while parsing save: could not allocate buffer\n");
return InternalError;
}
//Make sure bsonData is null terminated, since all string functions need null terminated strings //Make sure bsonData is null terminated, since all string functions need null terminated strings
//(bson_iterator_key returns a pointer into bsonData, which is then used with strcmp) //(bson_iterator_key returns a pointer into bsonData, which is then used with strcmp)
bsonData[bsonDataLen] = 0; bsonData[bsonDataLen] = 0;
if (BZ2_bzBuffToBuffDecompress((char*)bsonData, &bsonDataLen, (char*)(inputData+12), inputDataLen-12, 0, 0)) if (BZ2_bzBuffToBuffDecompress((char*)bsonData, &bsonDataLen, (char*)(inputData+12), inputDataLen-12, 0, 0))
{ throw ParseException(ParseException::Corrupt, "Unable to decompress");
fprintf(stderr, "Unable to decompress\n");
return Corrupt;
}
bson_init_data(&b, (char*)bsonData); bson_init_data(&b, (char*)bsonData);
bson_iterator_init(&iter, &b); bson_iterator_init(&iter, &b);
@@ -527,16 +518,17 @@ GameSave::ParseResult GameSave::readOPS(char * data, int dataLength)
goto fin; goto fin;
fail: fail:
//Clean up everything //Clean up everything
returnCode = Corrupt; bson_destroy(&b);
if(freeIndices)
free(freeIndices);
throw ParseException(ParseException::Corrupt, "Save data currupt");
fin: fin:
bson_destroy(&b); bson_destroy(&b);
if(freeIndices) if(freeIndices)
free(freeIndices); free(freeIndices);
return returnCode;
} }
GameSave::ParseResult GameSave::readPSv(char * data, int dataLength) void GameSave::readPSv(char * data, int dataLength)
{ {
unsigned char * d = NULL, * c = (unsigned char *)data; unsigned char * d = NULL, * c = (unsigned char *)data;
int q,i,j,k,x,y,p=0,*m=NULL, ver, pty, ty, legacy_beta=0, tempGrav = 0; int q,i,j,k,x,y,p=0,*m=NULL, ver, pty, ty, legacy_beta=0, tempGrav = 0;
@@ -568,14 +560,14 @@ GameSave::ParseResult GameSave::readPSv(char * data, int dataLength)
//This creates a problem for old clients, that display and "corrupt" error instead of a "newer version" error //This creates a problem for old clients, that display and "corrupt" error instead of a "newer version" error
if (dataLength<16) if (dataLength<16)
return Corrupt; throw ParseException(ParseException::Corrupt, "No save data");
if (!(c[2]==0x43 && c[1]==0x75 && c[0]==0x66) && !(c[2]==0x76 && c[1]==0x53 && c[0]==0x50)) if (!(c[2]==0x43 && c[1]==0x75 && c[0]==0x66) && !(c[2]==0x76 && c[1]==0x53 && c[0]==0x50))
return Corrupt; throw ParseException(ParseException::Corrupt, "Unknown format");
if (c[2]==0x76 && c[1]==0x53 && c[0]==0x50) { if (c[2]==0x76 && c[1]==0x53 && c[0]==0x50) {
new_format = 1; new_format = 1;
} }
if (c[4]>SAVE_VERSION) if (c[4]>SAVE_VERSION)
return WrongVersion; throw ParseException(ParseException::WrongVersion, "Save from newer version");
ver = c[4]; ver = c[4];
if (ver<34) if (ver<34)
@@ -615,23 +607,23 @@ GameSave::ParseResult GameSave::readPSv(char * data, int dataLength)
by0 = 0; by0 = 0;
if (c[5]!=CELL || bx0+bw>XRES/CELL || by0+bh>YRES/CELL) if (c[5]!=CELL || bx0+bw>XRES/CELL || by0+bh>YRES/CELL)
return InvalidDimensions; throw ParseException(ParseException::InvalidDimensions, "Save too large");
i = (unsigned)c[8]; i = (unsigned)c[8];
i |= ((unsigned)c[9])<<8; i |= ((unsigned)c[9])<<8;
i |= ((unsigned)c[10])<<16; i |= ((unsigned)c[10])<<16;
i |= ((unsigned)c[11])<<24; i |= ((unsigned)c[11])<<24;
d = (unsigned char *)malloc(i); d = (unsigned char *)malloc(i);
if (!d) if (!d)
return Corrupt; throw ParseException(ParseException::Corrupt, "Cannot allocate memory");
setSize(bw*CELL, bh*CELL); setSize(bw*CELL, bh*CELL);
if (BZ2_bzBuffToBuffDecompress((char *)d, (unsigned *)&i, (char *)(c+12), dataLength-12, 0, 0)) if (BZ2_bzBuffToBuffDecompress((char *)d, (unsigned *)&i, (char *)(c+12), dataLength-12, 0, 0))
return Corrupt; throw ParseException(ParseException::Corrupt, "Cannot decompress");
dataLength = i; dataLength = i;
if (dataLength < bw*bh) if (dataLength < bw*bh)
return Corrupt; throw ParseException(ParseException::Corrupt, "Save data corrupt (missing data)");
// normalize coordinates // normalize coordinates
x0 = bx0*CELL; x0 = bx0*CELL;
@@ -1098,15 +1090,14 @@ version1:
if (d) free(d); if (d) free(d);
if (fp) free(fp); if (fp) free(fp);
return OK; return;
corrupt: corrupt:
if (m) free(m); if (m) free(m);
if (d) free(d); if (d) free(d);
if (fp) free(fp); if (fp) free(fp);
return Corrupt; throw ParseException(ParseException::Corrupt, "Save data corrupt");
} }
char * GameSave::serialiseOPS(int & dataLength) char * GameSave::serialiseOPS(int & dataLength)
@@ -1447,12 +1438,6 @@ GameSave::~GameSave()
{ {
if(width && height) if(width && height)
{ {
/*if(particleMap)
{
for(int y = 0; y < height; y++)
delete[] particleMap[y];
delete[] particleMap;
}*/
if(particles) if(particles)
{ {
delete[] particles; delete[] particles;

View File

@@ -12,10 +12,22 @@
#include "Misc.h" #include "Misc.h"
#include "simulation/StorageClasses.h" #include "simulation/StorageClasses.h"
struct ParseException: public exception {
enum ParseResult { OK = 0, Corrupt, WrongVersion, InvalidDimensions, InternalError, MissingElement };
string message;
ParseResult result;
public:
ParseException(ParseResult result, string message_): message(message_), result(result) {}
const char * what() const throw()
{
return message.c_str();
}
~ParseException() throw() {};
};
class GameSave class GameSave
{ {
public: public:
enum ParseResult { OK = 0, Corrupt, WrongVersion, InvalidDimensions, InternalError, MissingElement };
int width, height; int width, height;
@@ -38,6 +50,7 @@ public:
//Signs //Signs
std::vector<sign> signs; std::vector<sign> signs;
GameSave();
GameSave(GameSave & save); GameSave(GameSave & save);
GameSave(int width, int height); GameSave(int width, int height);
GameSave(char * data, int dataSize); GameSave(char * data, int dataSize);
@@ -65,8 +78,8 @@ private:
float * fanVelYPtr; float * fanVelYPtr;
unsigned char * blockMapPtr; unsigned char * blockMapPtr;
ParseResult readOPS(char * data, int dataLength); void readOPS(char * data, int dataLength);
ParseResult readPSv(char * data, int dataLength); void readPSv(char * data, int dataLength);
char * serialiseOPS(int & dataSize); char * serialiseOPS(int & dataSize);
//serialisePSv(); //serialisePSv();
}; };

View File

@@ -320,6 +320,8 @@ void GameController::StampRegion(ui::Point point1, ui::Point point2)
newSave = gameModel->GetSimulation()->Save(point1.X, point1.Y, point2.X, point2.Y); newSave = gameModel->GetSimulation()->Save(point1.X, point1.Y, point2.X, point2.Y);
if(newSave) if(newSave)
gameModel->AddStamp(newSave); gameModel->AddStamp(newSave);
else
new ErrorMessage("Could not create stamp", "Error generating save file");
} }
void GameController::CopyRegion(ui::Point point1, ui::Point point2) void GameController::CopyRegion(ui::Point point1, ui::Point point2)

View File

@@ -434,7 +434,11 @@ void GameModel::SetStamp(Save * save)
{ {
if(stamp) if(stamp)
delete stamp; delete stamp;
stamp = new GameSave((char*)save->GetData(), save->GetDataLength()); try {
stamp = new GameSave((char*)save->GetData(), save->GetDataLength());
} catch (ParseException& e) {
stamp = NULL;
}
notifyStampChanged(); notifyStampChanged();
} }

View File

@@ -22,7 +22,8 @@ Thumbnail * SaveRenderer::Render(GameSave * save)
{ {
Thumbnail * tempThumb = NULL; Thumbnail * tempThumb = NULL;
int width, height; int width, height;
width, height = save->width, save->height; width = save->width/CELL;
height = save->height/CELL;
pixel * pData = NULL; pixel * pData = NULL;
pixel * dst; pixel * dst;
@@ -54,7 +55,12 @@ finish:
Thumbnail * SaveRenderer::Render(unsigned char * saveData, int dataSize) Thumbnail * SaveRenderer::Render(unsigned char * saveData, int dataSize)
{ {
GameSave * tempSave = new GameSave((char*)saveData, dataSize); GameSave * tempSave;
try {
tempSave = new GameSave((char*)saveData, dataSize);
} catch (exception & e) {
return NULL;
}
Thumbnail * thumb = Render(tempSave); Thumbnail * thumb = Render(tempSave);
delete tempSave; delete tempSave;
return thumb; return thumb;

View File

@@ -22,19 +22,27 @@ int Simulation::Load(int x, int y, GameSave * save)
for(int i = 0; i < NPART && i < save->particlesCount; i++) for(int i = 0; i < NPART && i < save->particlesCount; i++)
{ {
parts[i] = save->particles[i]; parts[i] = save->particles[i];
parts[i].x += (float)x;
parts[i].y += (float)y;
} }
parts_lastActiveIndex = NPART-1; parts_lastActiveIndex = NPART-1;
for(int i = 0; i < save->signs.size() && signs.size() < MAXSIGNS; i++) for(int i = 0; i < save->signs.size() && signs.size() < MAXSIGNS; i++)
{ {
signs.push_back(save->signs[i]); sign tempSign = save->signs[i];
tempSign.x += x;
tempSign.y += y;
signs.push_back(tempSign);
} }
for(int x = 0; x < save->width/CELL; x++) for(int blockX = 0; blockX < save->width/CELL; blockX++)
{ {
for(int y = 0; y < save->height/CELL; y++) for(int blockY = 0; blockY < save->height/CELL; blockY++)
{ {
bmap[y][x] = save->blockMap[y][x]; if(save->blockMap[blockY][blockX])
fvx[y][x] = save->fanVelX[y][x]; {
fvy[y][x] = save->fanVelY[y][x]; bmap[blockY+(y/CELL)][blockX+(x/CELL)] = save->blockMap[blockY][blockX];
fvx[blockY+(y/CELL)][blockX+(x/CELL)] = save->fanVelX[blockY][blockX];
fvy[blockY+(y/CELL)][blockX+(x/CELL)] = save->fanVelY[blockY][blockX];
}
} }
} }
return 0; return 0;
@@ -42,7 +50,7 @@ int Simulation::Load(int x, int y, GameSave * save)
GameSave * Simulation::Save() GameSave * Simulation::Save()
{ {
Save(0, 0, XRES, YRES); return Save(0, 0, XRES, YRES);
} }
GameSave * Simulation::Save(int x1, int y1, int x2, int y2) GameSave * Simulation::Save(int x1, int y1, int x2, int y2)
@@ -56,7 +64,10 @@ GameSave * Simulation::Save(int x1, int y1, int x2, int y2)
y = int(parts[i].y + 0.5f); y = int(parts[i].y + 0.5f);
if(parts[i].type && x >= x1 && y >= y1 && x < x2 && y < y2) if(parts[i].type && x >= x1 && y >= y1 && x < x2 && y < y2)
{ {
*newSave << parts[i]; Particle tempPart = parts[i];
tempPart.x -= x1;
tempPart.y -= y1;
*newSave << tempPart;
} }
} }
@@ -64,9 +75,14 @@ GameSave * Simulation::Save(int x1, int y1, int x2, int y2)
{ {
if(signs[i].text.length() && signs[i].x >= x1 && signs[i].y >= y1 && signs[i].x < x2 && signs[i].y < y2) if(signs[i].text.length() && signs[i].x >= x1 && signs[i].y >= y1 && signs[i].x < x2 && signs[i].y < y2)
{ {
*newSave << signs[i]; sign tempSign = signs[i];
tempSign.x -= x1;
tempSign.y -= y1;
*newSave << tempSign;
} }
} }
return newSave;
} }
/*int Simulation::Load(unsigned char * data, int dataLength) /*int Simulation::Load(unsigned char * data, int dataLength)