summaryrefslogtreecommitdiff
path: root/src/save.c
diff options
context:
space:
mode:
authorSimon Robertshaw <simon@Simons-Mac-Pro.local>2012-04-30 20:49:40 (GMT)
committer Simon Robertshaw <simon@Simons-Mac-Pro.local>2012-04-30 20:49:40 (GMT)
commit211770e8189b426287adad3d924c20cac203fbd1 (patch)
tree51b335ff8e73a4bbfb017a0de4dc7c2f68be05dd /src/save.c
parent8397b6e51aa817f2b33347bc801fdaee0b4d2700 (diff)
parent433c1881bc37ea257999b88eee920c19a92798c5 (diff)
downloadpowder-211770e8189b426287adad3d924c20cac203fbd1.zip
powder-211770e8189b426287adad3d924c20cac203fbd1.tar.gz
Merge branch 'master' of github.com:FacialTurd/The-Powder-Toy
Diffstat (limited to 'src/save.c')
-rw-r--r--src/save.c138
1 files changed, 123 insertions, 15 deletions
diff --git a/src/save.c b/src/save.c
index a96cb05..56b7424 100644
--- a/src/save.c
+++ b/src/save.c
@@ -440,9 +440,11 @@ fin:
void *build_save_OPS(int *size, int orig_x0, int orig_y0, int orig_w, int orig_h, unsigned char bmap[YRES/CELL][XRES/CELL], float vx[YRES/CELL][XRES/CELL], float vy[YRES/CELL][XRES/CELL], float pv[YRES/CELL][XRES/CELL], float fvx[YRES/CELL][XRES/CELL], float fvy[YRES/CELL][XRES/CELL], sign signs[MAXSIGNS], void* o_partsptr)
{
particle *partsptr = o_partsptr;
- unsigned char *partsData = NULL, *partsPosData = NULL, *fanData = NULL, *wallData = NULL, *finalData = NULL, *outputData = NULL;
+ unsigned char *partsData = NULL, *partsPosData = NULL, *fanData = NULL, *wallData = NULL, *finalData = NULL, *outputData = NULL, *soapLinkData = NULL;
unsigned *partsPosLink = NULL, *partsPosFirstMap = NULL, *partsPosCount = NULL, *partsPosLastMap = NULL;
- int partsDataLen, partsPosDataLen, fanDataLen, wallDataLen, finalDataLen, outputDataLen;
+ unsigned partsCount = 0, *partsSaveIndex = NULL;
+ unsigned *elementCount = calloc(PT_NUM, sizeof(unsigned));
+ int partsDataLen, partsPosDataLen, fanDataLen, wallDataLen, finalDataLen, outputDataLen, soapLinkDataLen;
int blockX, blockY, blockW, blockH, fullX, fullY, fullW, fullH;
int x, y, i, wallDataFound = 0;
int posCount, signsCount;
@@ -557,6 +559,8 @@ void *build_save_OPS(int *size, int orig_x0, int orig_y0, int orig_w, int orig_h
*/
partsData = malloc(NPART * (sizeof(particle)+1));
partsDataLen = 0;
+ partsSaveIndex = calloc(NPART, sizeof(unsigned));
+ partsCount = 0;
for (y=0;y<fullH;y++)
{
for (x=0;x<fullW;x++)
@@ -573,8 +577,12 @@ void *build_save_OPS(int *size, int orig_x0, int orig_y0, int orig_w, int orig_h
//Turn pmap entry into a partsptr index
i = i>>8;
+ //Store saved particle index+1 for this partsptr index (0 means not saved)
+ partsSaveIndex[i] = (partsCount++) + 1;
+
//Type (required)
partsData[partsDataLen++] = partsptr[i].type;
+ elementCount[partsptr[i].type]++;
//Location of the field descriptor
fieldDescLoc = partsDataLen++;
@@ -679,6 +687,47 @@ void *build_save_OPS(int *size, int orig_x0, int orig_y0, int orig_w, int orig_h
}
}
}
+
+ soapLinkData = malloc(3*elementCount[PT_SOAP]);
+ soapLinkDataLen = 0;
+ //Iterate through particles in the same order that they were saved
+ for (y=0;y<fullH;y++)
+ {
+ for (x=0;x<fullW;x++)
+ {
+ //Find the first particle in this position
+ i = partsPosFirstMap[y*fullW + x];
+
+ //Loop while there is a pmap entry
+ while (i)
+ {
+ //Turn pmap entry into a partsptr index
+ i = i>>8;
+
+ if (partsptr[i].type==PT_SOAP)
+ {
+ //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 ((partsptr[i].ctype&2) && partsptr[i].tmp>=0 && partsptr[i].tmp<NPART)
+ {
+ linkedIndex = partsSaveIndex[partsptr[i].tmp];
+ }
+ 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];
+ }
+ }
+ }
+ if(!soapLinkDataLen)
+ {
+ free(soapLinkData);
+ soapLinkData = NULL;
+ }
if(!partsDataLen)
{
free(partsData);
@@ -704,10 +753,12 @@ void *build_save_OPS(int *size, int orig_x0, int orig_y0, int orig_w, int orig_h
bson_append_binary(&b, "wallMap", BSON_BIN_USER, wallData, wallDataLen);
if(fanData)
bson_append_binary(&b, "fanMap", BSON_BIN_USER, fanData, fanDataLen);
+ if(soapLinkData)
+ bson_append_binary(&b, "soapLinks", BSON_BIN_USER, soapLinkData, soapLinkDataLen);
signsCount = 0;
for(i = 0; i < MAXSIGNS; i++)
{
- if(signs[i].text[0] && signs[i].x>=fullX && signs[i].x<=fullX+fullW && signs[i].y>=fullY && signs[i].y<=fullY+fullH)
+ if(signs[i].text[0] && signs[i].x>=orig_x0 && signs[i].x<=orig_x0+orig_w && signs[i].y>=orig_y0 && signs[i].y<=orig_y0+orig_h)
{
signsCount++;
}
@@ -717,7 +768,7 @@ void *build_save_OPS(int *size, int orig_x0, int orig_y0, int orig_w, int orig_h
bson_append_start_array(&b, "signs");
for(i = 0; i < MAXSIGNS; i++)
{
- if(signs[i].text[0] && signs[i].x>=fullX && signs[i].x<=fullX+fullW && signs[i].y>=fullY && signs[i].y<=fullY+fullH)
+ if(signs[i].text[0] && signs[i].x>=orig_x0 && signs[i].x<=orig_x0+orig_w && signs[i].y>=orig_y0 && signs[i].y<=orig_y0+orig_h)
{
bson_append_start_object(&b, "sign");
bson_append_string(&b, "text", signs[i].text);
@@ -770,6 +821,12 @@ fin:
free(wallData);
if(fanData)
free(fanData);
+ if (elementCount)
+ free(elementCount);
+ if (partsSaveIndex)
+ free(partsSaveIndex);
+ if (soapLinkData)
+ free(soapLinkData);
return outputData;
}
@@ -777,8 +834,9 @@ fin:
int parse_save_OPS(void *save, int size, int replace, int x0, int y0, unsigned char bmap[YRES/CELL][XRES/CELL], float vx[YRES/CELL][XRES/CELL], float vy[YRES/CELL][XRES/CELL], float pv[YRES/CELL][XRES/CELL], float fvx[YRES/CELL][XRES/CELL], float fvy[YRES/CELL][XRES/CELL], sign signs[MAXSIGNS], void* o_partsptr, unsigned pmap[YRES][XRES])
{
particle *partsptr = o_partsptr;
- unsigned char * inputData = save, *bsonData = NULL, *partsData = NULL, *partsPosData = NULL, *fanData = NULL, *wallData = NULL;
- int inputDataLen = size, bsonDataLen = 0, partsDataLen, partsPosDataLen, fanDataLen, wallDataLen;
+ unsigned char * inputData = save, *bsonData = NULL, *partsData = NULL, *partsPosData = NULL, *fanData = NULL, *wallData = NULL, *soapLinkData = NULL;
+ int inputDataLen = size, bsonDataLen = 0, partsDataLen, partsPosDataLen, fanDataLen, wallDataLen, soapLinkDataLen;
+ unsigned partsCount = 0, *partsSimIndex = NULL;
int i, freeIndicesCount, x, y, returnCode = 0, j;
int *freeIndices = NULL;
int blockX, blockY, blockW, blockH, fullX, fullY, fullW, fullH;
@@ -874,7 +932,7 @@ int parse_save_OPS(void *save, int size, int replace, int x0, int y0, unsigned c
{
if(strcmp(bson_iterator_key(&signiter), "text")==0 && bson_iterator_type(&signiter)==BSON_STRING)
{
- strcpy(signs[i].text, bson_iterator_string(&signiter));
+ strncpy(signs[i].text, bson_iterator_string(&signiter), 255);
clean_text(signs[i].text, 158-14);
}
else if(strcmp(bson_iterator_key(&signiter), "justification")==0 && bson_iterator_type(&signiter)==BSON_INT)
@@ -951,6 +1009,17 @@ int parse_save_OPS(void *save, int size, int replace, int x0, int y0, unsigned c
fprintf(stderr, "Invalid datatype of fan data: %d[%d] %d[%d] %d[%d]\n", bson_iterator_type(&iter), bson_iterator_type(&iter)==BSON_BINDATA, (unsigned char)bson_iterator_bin_type(&iter), ((unsigned char)bson_iterator_bin_type(&iter))==BSON_BIN_USER, bson_iterator_bin_len(&iter), bson_iterator_bin_len(&iter)>0);
}
}
+ else if(strcmp(bson_iterator_key(&iter), "soapLinks")==0)
+ {
+ if(bson_iterator_type(&iter)==BSON_BINDATA && ((unsigned char)bson_iterator_bin_type(&iter))==BSON_BIN_USER && (soapLinkDataLen = bson_iterator_bin_len(&iter)) > 0)
+ {
+ soapLinkData = bson_iterator_bin_data(&iter);
+ }
+ else
+ {
+ fprintf(stderr, "Invalid datatype of soap data: %d[%d] %d[%d] %d[%d]\n", bson_iterator_type(&iter), bson_iterator_type(&iter)==BSON_BINDATA, (unsigned char)bson_iterator_bin_type(&iter), ((unsigned char)bson_iterator_bin_type(&iter))==BSON_BIN_USER, bson_iterator_bin_len(&iter), bson_iterator_bin_len(&iter)>0);
+ }
+ }
else if(strcmp(bson_iterator_key(&iter), "legacyEnable")==0 && replace)
{
if(bson_iterator_type(&iter)==BSON_BOOL)
@@ -1102,6 +1171,8 @@ int parse_save_OPS(void *save, int size, int replace, int x0, int y0, unsigned c
parts_lastActiveIndex = NPART-1;
freeIndicesCount = 0;
freeIndices = calloc(sizeof(int), NPART);
+ partsSimIndex = calloc(NPART, sizeof(unsigned));
+ partsCount = 0;
for (i = 0; i<NPART; i++)
{
//Ensure ALL parts (even photons) are in the pmap so we can overwrite, keep a track of indices we can use
@@ -1141,7 +1212,7 @@ int parse_save_OPS(void *save, int size, int replace, int x0, int y0, unsigned c
}
if(partsData[i] >= PT_NUM)
partsData[i] = PT_DMND; //Replace all invalid elements with diamond
- if(pmap[y][x])
+ if(pmap[y][x] && posCount==0) // Check posCount to make sure an existing particle is not replaced twice if two particles are saved in that position
{
//Replace existing particle or allocated block
newIndex = pmap[y][x]>>8;
@@ -1158,7 +1229,10 @@ int parse_save_OPS(void *save, int size, int replace, int x0, int y0, unsigned c
}
if(newIndex < 0 || newIndex >= NPART)
goto fail;
-
+
+ //Store partsptr index+1 for this saved particle index (0 means not loaded)
+ partsSimIndex[partsCount++] = newIndex+1;
+
//Clear the particle, ready for our new properties
memset(&(partsptr[newIndex]), 0, sizeof(particle));
@@ -1284,11 +1358,43 @@ int parse_save_OPS(void *save, int size, int replace, int x0, int y0, unsigned c
STKM_init_legs(&(fighters[fcount]), newIndex);
}
}
+ else if (partsptr[newIndex].type == PT_SOAP)
+ {
+ //Clear soap links, links will be added back in if soapLinkData is present
+ partsptr[newIndex].ctype &= ~6;
+ }
if (!ptypes[partsptr[newIndex].type].enabled)
partsptr[newIndex].type = PT_NONE;
}
}
}
+ if (soapLinkData)
+ {
+ int soapLinkDataPos = 0;
+ for (i=0; i<partsCount; i++)
+ {
+ if (partsSimIndex[i] && partsptr[partsSimIndex[i]-1].type == PT_SOAP)
+ {
+ // Get the index of the particle forward linked from this one, if present in the save data
+ int linkedIndex = 0;
+ if (soapLinkDataPos+3 > soapLinkDataLen) break;
+ linkedIndex |= soapLinkData[soapLinkDataPos++]<<16;
+ linkedIndex |= soapLinkData[soapLinkDataPos++]<<8;
+ linkedIndex |= soapLinkData[soapLinkDataPos++];
+ // All indexes in soapLinkData and partsSimIndex have 1 added to them (0 means not saved/loaded)
+ if (!linkedIndex || linkedIndex-1>=partsCount || !partsSimIndex[linkedIndex-1])
+ continue;
+ linkedIndex = partsSimIndex[linkedIndex-1]-1;
+ newIndex = partsSimIndex[i]-1;
+
+ //Attach the two particles
+ partsptr[newIndex].ctype |= 2;
+ partsptr[newIndex].tmp = linkedIndex;
+ partsptr[linkedIndex].ctype |= 4;
+ partsptr[linkedIndex].tmp2 = newIndex;
+ }
+ }
+ }
}
goto fin;
fail:
@@ -1298,6 +1404,8 @@ fin:
bson_destroy(&b);
if(freeIndices)
free(freeIndices);
+ if(partsSimIndex)
+ free(partsSimIndex);
return returnCode;
}
@@ -1580,7 +1688,7 @@ void *build_save_PSv(int *size, int orig_x0, int orig_y0, int orig_w, int orig_h
for (j=0; j<w*h; j++)
{
i = m[j];
- if (i && (parts[i-1].type==PT_PBCN)) {
+ if (i && (parts[i-1].type==PT_PBCN || parts[i-1].type==PT_TRON)) {
//Save tmp2
d[p++] = parts[i-1].tmp2;
}
@@ -1638,14 +1746,14 @@ void *build_save_PSv(int *size, int orig_x0, int orig_y0, int orig_w, int orig_h
j = 0;
for (i=0; i<MAXSIGNS; i++)
if (signs[i].text[0] &&
- signs[i].x>=x0 && signs[i].x<x0+w &&
- signs[i].y>=y0 && signs[i].y<y0+h)
+ signs[i].x>=orig_x0 && signs[i].x<orig_x0+orig_w &&
+ signs[i].y>=orig_y0 && signs[i].y<orig_y0+orig_h)
j++;
d[p++] = j;
for (i=0; i<MAXSIGNS; i++)
if (signs[i].text[0] &&
- signs[i].x>=x0 && signs[i].x<x0+w &&
- signs[i].y>=y0 && signs[i].y<y0+h)
+ signs[i].x>=orig_x0 && signs[i].x<orig_x0+orig_w &&
+ signs[i].y>=orig_y0 && signs[i].y<orig_y0+orig_h)
{
d[p++] = (signs[i].x-x0);
d[p++] = (signs[i].x-x0)>>8;
@@ -1963,7 +2071,7 @@ int parse_save_PSv(void *save, int size, int replace, int x0, int y0, unsigned c
{
i = m[j];
ty = d[pty+j];
- if (i && ty==PT_PBCN)
+ if (i && (ty==PT_PBCN || (ty==PT_TRON && ver>=77)))
{
if (p >= size)
goto corrupt;