mirror of
https://github.com/The-Powder-Toy/The-Powder-Toy.git
synced 2025-09-03 04:52:35 +02:00
Saving and loading at position, yuse exceptions for parsing saves
This commit is contained in:
@@ -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;
|
||||||
|
@@ -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();
|
||||||
};
|
};
|
||||||
|
@@ -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)
|
||||||
|
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
@@ -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)
|
||||||
|
Reference in New Issue
Block a user