Skip to content

Commit

Permalink
Changes to save format and PIPE
Browse files Browse the repository at this point in the history
Update save format to optionally store type as two bits
PIPE now stores element in ctype
Disallow uploading saves using two bytes in type or other fields
update save format to store pmapbits and automatically convert data
  • Loading branch information
jacob1 committed Jan 1, 2018
1 parent 0c8c4de commit b5159ab
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 98 deletions.
6 changes: 3 additions & 3 deletions src/Config.h
Expand Up @@ -34,9 +34,9 @@
#define MOD_ID 0
#endif

#ifdef SNAPSHOT
#define FUTURE_SAVE_VERSION 92
#define FUTURE_MINOR_VERSION 1
#if defined(SNAPSHOT) || defined(DEBUG)
#define FUTURE_SAVE_VERSION 93
#define FUTURE_MINOR_VERSION 0
#endif
//VersionInfoEnd

Expand Down
6 changes: 3 additions & 3 deletions src/client/Client.cpp
Expand Up @@ -1021,10 +1021,10 @@ RequestStatus Client::UploadSave(SaveInfo & save)
lastError = "Cannot serialize game save";
return RequestFailure;
}
#ifdef SNAPSHOT
else if (save.gameSave->fromNewerVersion && save.GetPublished())
#if defined(SNAPSHOT) || defined(DEBUG)
else if (save.gameSave->fromNewerVersion)
{
lastError = "Cannot publish save";
lastError = "Cannot upload save, incompatible with latest release version";
return RequestFailure;
}
#endif
Expand Down
78 changes: 70 additions & 8 deletions src/client/GameSave.cpp
Expand Up @@ -28,6 +28,7 @@ GameSave::GameSave(GameSave & save):
edgeMode(save.edgeMode),
signs(save.signs),
palette(save.palette),
pmapbits(save.pmapbits),
expanded(save.expanded),
hasOriginalData(save.hasOriginalData),
originalData(save.originalData)
Expand Down Expand Up @@ -141,6 +142,7 @@ GameSave::GameSave(char * data, int dataSize)
//Collapse();
}

// Called on every new GameSave, including the copy constructor
void GameSave::InitData()
{
blockMap = NULL;
Expand All @@ -157,6 +159,7 @@ void GameSave::InitData()
authors.clear();
}

// Called on every new GameSave, except the copy constructor
void GameSave::InitVars()
{
waterEEnabled = false;
Expand All @@ -168,6 +171,7 @@ void GameSave::InitVars()
airMode = 0;
edgeMode = 0;
translated.x = translated.y = 0;
pmapbits = 8; // default to 8 bits for older saves
}

bool GameSave::Collapsed()
Expand Down Expand Up @@ -563,6 +567,7 @@ void GameSave::readOPS(char * data, int dataLength)
unsigned partsCount = 0;
unsigned int blockX, blockY, blockW, blockH, fullX, fullY, fullW, fullH;
int savedVersion = inputData[4];
bool fakeNewerVersion = false; // used for development builds only

bson b;
b.data = NULL;
Expand Down Expand Up @@ -649,6 +654,7 @@ void GameSave::readOPS(char * data, int dataLength)
CheckBsonFieldInt(iter, "gravityMode", &gravityMode);
CheckBsonFieldInt(iter, "airMode", &airMode);
CheckBsonFieldInt(iter, "edgeMode", &edgeMode);
CheckBsonFieldInt(iter, "pmapbits", &pmapbits);
if (!strcmp(bson_iterator_key(&iter), "signs"))
{
if (bson_iterator_type(&iter)==BSON_ARRAY)
Expand Down Expand Up @@ -739,7 +745,7 @@ void GameSave::readOPS(char * data, int dataLength)
fprintf(stderr, "Wrong type for %s\n", bson_iterator_key(&iter));
}
}
#ifdef SNAPSHOT
#if defined(SNAPSHOT) || defined(DEBUG)
if (major > FUTURE_SAVE_VERSION || (major == FUTURE_SAVE_VERSION && minor > FUTURE_MINOR_VERSION))
#else
if (major > SAVE_VERSION || (major == SAVE_VERSION && minor > MINOR_VERSION))
Expand All @@ -749,6 +755,10 @@ void GameSave::readOPS(char * data, int dataLength)
errorMessage << "Save from a newer version: Requires version " << major << "." << minor;
throw ParseException(ParseException::WrongVersion, errorMessage.str());
}
#if defined(SNAPSHOT) || defined(DEBUG)
else if (major > SAVE_VERSION || (major == SAVE_VERSION && minor > MINOR_VERSION))
fakeNewerVersion = true;
#endif
}
else
{
Expand Down Expand Up @@ -956,6 +966,10 @@ void GameSave::readOPS(char * data, int dataLength)
particles[newIndex].y = y;
i+=3;

// Read type (2nd byte)
if (fieldDescriptor & 0x4000)
particles[newIndex].type |= (((unsigned)partsData[i++]) << 8);

//Read temp
if(fieldDescriptor & 0x01)
{
Expand Down Expand Up @@ -1185,6 +1199,16 @@ void GameSave::readOPS(char * data, int dataLength)
}
}
break;
case PT_PIPE:
case PT_PPIP:
if (savedVersion < 93 && !fakeNewerVersion)
{
if (particles[newIndex].ctype == 1)
particles[newIndex].tmp |= 0x00020000; //PFLAG_INITIALIZING
particles[newIndex].tmp |= (particles[newIndex].ctype-1)<<18;
particles[newIndex].ctype = particles[newIndex].tmp&0xFF;
}
break;
}
//note: PSv was used in version 77.0 and every version before, add something in PSv too if the element is that old
newIndex++;
Expand Down Expand Up @@ -1841,6 +1865,14 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
}
}
}
// Version 93.0
if (particles[i-1].type == PT_PIPE || particles[i-1].type == PT_PPIP)
{
if (particles[i-1].ctype == 1)
particles[i-1].tmp |= 0x00020000; //PFLAG_INITIALIZING
particles[i-1].tmp |= (particles[i-1].ctype-1)<<18;
particles[i-1].ctype = particles[i-1].tmp&0xFF;
}
}
}

Expand Down Expand Up @@ -2020,9 +2052,11 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)

//Copy parts data
/* Field descriptor format:
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 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|
| 0 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| RESERVED | type[2] | pavg | tmp[3+4] | tmp2[2] | tmp2 | ctype[2] | vy | vx | decorations | 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
last bit is reserved. If necessary, use it to signify that fieldDescriptor will have another byte
That way, if we ever need a 17th bit, we won't have to change the save format
*/
auto partsData = std::unique_ptr<unsigned char[]>(new unsigned char[NPART * (sizeof(Particle)+1)]);
unsigned int partsDataLen = 0;
Expand Down Expand Up @@ -2057,6 +2091,15 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
fieldDescLoc = partsDataLen++;
partsDataLen++;

// Extra type byte if necessary
if (particles[i].type & 0xFF00)
{
partsData[partsDataLen++] = particles[i].type >> 8;
fieldDesc |= 1 << 14;
RESTRICTVERSION(93, 0);
fromNewerVersion = true; // TODO: remove on 93.0 release
}

//Extra Temperature (2nd byte optional, 1st required), 1 to 2 bytes
//Store temperature as an offset of 21C(294.15K) or go into a 16byte int and store the whole thing
if(fabs(particles[i].temp-294.15f)<127)
Expand Down Expand Up @@ -2193,12 +2236,33 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
|| particles[i].type == PT_RFRG || particles[i].type == PT_RFGL || particles[i].type == PT_LSNS)
{
RESTRICTVERSION(92, 0);
fromNewerVersion = true;
}
else if ((particles[i].type == PT_FRAY || particles[i].type == PT_INVIS) && particles[i].tmp)
{
RESTRICTVERSION(92, 0);
fromNewerVersion = true;
}
else if (particles[i].type == PT_PIPE || particles[i].type == PT_PPIP)
{
RESTRICTVERSION(93, 0);
fromNewerVersion = true; // TODO: remove on 93.0 release
}
if (PMAPBITS > 8)
{
if (Simulation::TypeInCtype(particles[i].type) && particles[i].ctype > 0xFF)
{
RESTRICTVERSION(93, 0);
fromNewerVersion = true; // TODO: remove on 93.0 release
}
else if (Simulation::TypeInTmp(particles[i].type) && particles[i].tmp > 0xFF)
{
RESTRICTVERSION(93, 0);
fromNewerVersion = true; // TODO: remove on 93.0 release
}
else if (Simulation::TypeInTmp2(particles[i].type) && particles[i].tmp2 > 0xFF)
{
RESTRICTVERSION(93, 0);
fromNewerVersion = true; // TODO: remove on 93.0 release
}
}

//Get the pmap entry for the next particle in the same position
Expand Down Expand Up @@ -2286,9 +2350,7 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
bson_append_int(&b, "airMode", airMode);
bson_append_int(&b, "edgeMode", edgeMode);

//bson_append_int(&b, "leftSelectedElement", sl);
//bson_append_int(&b, "rightSelectedElement", sr);
//bson_append_int(&b, "activeMenu", active_menu);
bson_append_int(&b, "pmapbits", pmapbits);
if (partsData && partsDataLen)
{
bson_append_binary(&b, "parts", BSON_BIN_USER, (const char *)partsData.get(), partsDataLen);
Expand Down
2 changes: 2 additions & 0 deletions src/client/GameSave.h
Expand Up @@ -78,6 +78,8 @@ class GameSave
// author information
Json::Value authors;

int pmapbits;

GameSave();
GameSave(GameSave & save);
GameSave(int width, int height);
Expand Down
4 changes: 1 addition & 3 deletions src/gui/game/GameView.cpp
Expand Up @@ -2292,8 +2292,6 @@ void GameView::OnDraw()
if (type)
{
int ctype = sample.particle.ctype;
if (type == PT_PIPE || type == PT_PPIP)
ctype = TYP(sample.particle.tmp);

if (type == PT_PHOT || type == PT_BIZR || type == PT_BIZRG || type == PT_BIZRS || type == PT_FILT || type == PT_BRAY || type == PT_C5)
wavelengthGfx = (ctype&0x3FFFFFFF);
Expand Down Expand Up @@ -2322,7 +2320,7 @@ void GameView::OnDraw()
sampleInfo << " (" << ctype << ")";
// Some elements store extra LIFE info in upper bits of ctype, instead of tmp/tmp2
else if (type == PT_CRAY || type == PT_DRAY || type == PT_CONV)
sampleInfo << " (" << c->ElementResolve(TYP(type), ID(ctype)) << ")";
sampleInfo << " (" << c->ElementResolve(TYP(ctype), ID(ctype)) << ")";
else if (c->IsValidElement(ctype))
sampleInfo << " (" << c->ElementResolve(ctype, -1) << ")";
else
Expand Down
2 changes: 1 addition & 1 deletion src/simulation/Elements.h
Expand Up @@ -51,7 +51,7 @@
#define OLD_PT_WIND 147

// Change this to change the amount of bits used to store type in pmap (and a few elements such as PIPE and CRAY)
#define PMAPBITS 8
#define PMAPBITS 9
#define PMAPMASK ((1<<PMAPBITS)-1)
#define ID(r) ((r)>>PMAPBITS)
#define TYP(r) ((r)&PMAPMASK)
Expand Down

0 comments on commit b5159ab

Please sign in to comment.