From 8fae7dbade0a83c86f92723149fb484acd99b951 Mon Sep 17 00:00:00 2001 From: Simon Robertshaw Date: Wed, 6 Jun 2012 01:46:13 +0100 Subject: [PATCH] Saving and loading at position, yuse exceptions for parsing saves --- src/client/GameSave.cpp | 73 +++++++++++++-------------------- src/client/GameSave.h | 19 +++++++-- src/game/GameController.cpp | 2 + src/game/GameModel.cpp | 6 ++- src/simulation/SaveRenderer.cpp | 10 ++++- src/simulation/Simulation.cpp | 34 +++++++++++---- 6 files changed, 85 insertions(+), 59 deletions(-) diff --git a/src/client/GameSave.cpp b/src/client/GameSave.cpp index ed742b08f..9c7cf5e4e 100644 --- a/src/client/GameSave.cpp +++ b/src/client/GameSave.cpp @@ -13,7 +13,6 @@ #include "GameSave.h" #include "SimulationData.h" - GameSave::GameSave(GameSave & save) : waterEEnabled(save.waterEEnabled), legacyEnable(save.legacyEnable), @@ -38,7 +37,14 @@ GameSave::GameSave(int width, int height) 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) @@ -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 int inputDataLen = dataLength, bsonDataLen = 0, partsDataLen, partsPosDataLen, fanDataLen, wallDataLen; int i, freeIndicesCount, x, y, j; - ParseResult returnCode = OK; int *freeIndices = NULL; int blockX, blockY, blockW, blockH, fullX, fullY, fullW, fullH; bson b; @@ -99,24 +104,15 @@ GameSave::ParseResult GameSave::readOPS(char * data, int dataLength) //From newer version if(inputData[4] > SAVE_VERSION) - { - fprintf(stderr, "Save from newer version\n"); - return WrongVersion; - } + throw ParseException(ParseException::WrongVersion, "Save from newer version"); //Incompatible cell size if(inputData[5] > CELL) - { - fprintf(stderr, "Cell size mismatch\n"); - return InvalidDimensions; - } + throw ParseException(ParseException::InvalidDimensions, "Incorrect CELL size"); //Too large/off screen if(blockX+blockW > XRES/CELL || blockY+blockH > YRES/CELL) - { - fprintf(stderr, "Save too large\n"); - return InvalidDimensions; - } + throw ParseException(ParseException::InvalidDimensions, "Save too large"); setSize(fullW, fullH); @@ -127,19 +123,14 @@ GameSave::ParseResult GameSave::readOPS(char * data, int dataLength) bsonData = (unsigned char*)malloc(bsonDataLen+1); if(!bsonData) - { - fprintf(stderr, "Internal error while parsing save: could not allocate buffer\n"); - return InternalError; - } + throw ParseException(ParseException::InternalError, "Unable to allocate memory"); + //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) bsonData[bsonDataLen] = 0; if (BZ2_bzBuffToBuffDecompress((char*)bsonData, &bsonDataLen, (char*)(inputData+12), inputDataLen-12, 0, 0)) - { - fprintf(stderr, "Unable to decompress\n"); - return Corrupt; - } + throw ParseException(ParseException::Corrupt, "Unable to decompress"); bson_init_data(&b, (char*)bsonData); bson_iterator_init(&iter, &b); @@ -527,16 +518,17 @@ GameSave::ParseResult GameSave::readOPS(char * data, int dataLength) goto fin; fail: //Clean up everything - returnCode = Corrupt; + bson_destroy(&b); + if(freeIndices) + free(freeIndices); + throw ParseException(ParseException::Corrupt, "Save data currupt"); fin: bson_destroy(&b); if(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; 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 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)) - return Corrupt; + throw ParseException(ParseException::Corrupt, "Unknown format"); if (c[2]==0x76 && c[1]==0x53 && c[0]==0x50) { new_format = 1; } if (c[4]>SAVE_VERSION) - return WrongVersion; + throw ParseException(ParseException::WrongVersion, "Save from newer version"); ver = c[4]; if (ver<34) @@ -615,23 +607,23 @@ GameSave::ParseResult GameSave::readPSv(char * data, int dataLength) by0 = 0; 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[9])<<8; i |= ((unsigned)c[10])<<16; i |= ((unsigned)c[11])<<24; d = (unsigned char *)malloc(i); if (!d) - return Corrupt; + throw ParseException(ParseException::Corrupt, "Cannot allocate memory"); setSize(bw*CELL, bh*CELL); if (BZ2_bzBuffToBuffDecompress((char *)d, (unsigned *)&i, (char *)(c+12), dataLength-12, 0, 0)) - return Corrupt; + throw ParseException(ParseException::Corrupt, "Cannot decompress"); dataLength = i; if (dataLength < bw*bh) - return Corrupt; + throw ParseException(ParseException::Corrupt, "Save data corrupt (missing data)"); // normalize coordinates x0 = bx0*CELL; @@ -1098,15 +1090,14 @@ version1: if (d) free(d); if (fp) free(fp); - return OK; + return; corrupt: if (m) free(m); if (d) free(d); if (fp) free(fp); - return Corrupt; - + throw ParseException(ParseException::Corrupt, "Save data corrupt"); } char * GameSave::serialiseOPS(int & dataLength) @@ -1447,12 +1438,6 @@ GameSave::~GameSave() { if(width && height) { - /*if(particleMap) - { - for(int y = 0; y < height; y++) - delete[] particleMap[y]; - delete[] particleMap; - }*/ if(particles) { delete[] particles; diff --git a/src/client/GameSave.h b/src/client/GameSave.h index 0c5040517..2978f5200 100644 --- a/src/client/GameSave.h +++ b/src/client/GameSave.h @@ -12,10 +12,22 @@ #include "Misc.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 { public: - enum ParseResult { OK = 0, Corrupt, WrongVersion, InvalidDimensions, InternalError, MissingElement }; int width, height; @@ -38,6 +50,7 @@ public: //Signs std::vector signs; + GameSave(); GameSave(GameSave & save); GameSave(int width, int height); GameSave(char * data, int dataSize); @@ -65,8 +78,8 @@ private: float * fanVelYPtr; unsigned char * blockMapPtr; - ParseResult readOPS(char * data, int dataLength); - ParseResult readPSv(char * data, int dataLength); + void readOPS(char * data, int dataLength); + void readPSv(char * data, int dataLength); char * serialiseOPS(int & dataSize); //serialisePSv(); }; diff --git a/src/game/GameController.cpp b/src/game/GameController.cpp index 9580d2c64..dff6c184c 100644 --- a/src/game/GameController.cpp +++ b/src/game/GameController.cpp @@ -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); if(newSave) gameModel->AddStamp(newSave); + else + new ErrorMessage("Could not create stamp", "Error generating save file"); } void GameController::CopyRegion(ui::Point point1, ui::Point point2) diff --git a/src/game/GameModel.cpp b/src/game/GameModel.cpp index 08bd0ecdf..966eca781 100644 --- a/src/game/GameModel.cpp +++ b/src/game/GameModel.cpp @@ -434,7 +434,11 @@ void GameModel::SetStamp(Save * save) { if(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(); } diff --git a/src/simulation/SaveRenderer.cpp b/src/simulation/SaveRenderer.cpp index 52dcfaf92..54f838b9e 100644 --- a/src/simulation/SaveRenderer.cpp +++ b/src/simulation/SaveRenderer.cpp @@ -22,7 +22,8 @@ Thumbnail * SaveRenderer::Render(GameSave * save) { Thumbnail * tempThumb = NULL; int width, height; - width, height = save->width, save->height; + width = save->width/CELL; + height = save->height/CELL; pixel * pData = NULL; pixel * dst; @@ -54,7 +55,12 @@ finish: 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); delete tempSave; return thumb; diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index 8fb439477..063b880f6 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -22,19 +22,27 @@ int Simulation::Load(int x, int y, GameSave * save) for(int i = 0; i < NPART && i < save->particlesCount; i++) { parts[i] = save->particles[i]; + parts[i].x += (float)x; + parts[i].y += (float)y; } parts_lastActiveIndex = NPART-1; 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]; - fvx[y][x] = save->fanVelX[y][x]; - fvy[y][x] = save->fanVelY[y][x]; + if(save->blockMap[blockY][blockX]) + { + 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; @@ -42,7 +50,7 @@ int Simulation::Load(int x, int y, GameSave * 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) @@ -56,7 +64,10 @@ GameSave * Simulation::Save(int x1, int y1, int x2, int y2) y = int(parts[i].y + 0.5f); 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) { - *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)