diff --git a/mcpetbackup.c b/mcpetbackup.c index 65d6322..9364778 100644 --- a/mcpetbackup.c +++ b/mcpetbackup.c @@ -1,5 +1,6 @@ #include #include +#include #include "nbt.h" #include "chunk.h" @@ -7,19 +8,29 @@ enum paramIndex { UNKNOWN = 0, + HELP, REGION, SAVE, LOAD, NAME, - OWNER + OWNER, + COORDS }; +typedef struct Coords { + int x; + int y; + int z; +} Coords; + static struct option longopts[] = { + { "help", no_argument, NULL, HELP }, { "regiondata", required_argument, NULL, REGION }, { "save", required_argument, NULL, SAVE }, { "load", required_argument, NULL, LOAD }, { "name", required_argument, NULL, NAME }, { "owner", required_argument, NULL, OWNER }, + { "coords", required_argument, NULL, COORDS }, { NULL, 0, NULL, UNKNOWN } }; @@ -102,7 +113,7 @@ int getEntitiesTag(TagCompound* chunkRoot,Tag** entities) { int found = 0; for(int i = 0; i < chunkRoot->numTags; ++i) { t = &(chunkRoot->list[i]); - if(!strcmp(t->name,"Level")) { + if(!strncmp(t->name,"Level",t->nameLength)) { found = 1; break; } @@ -116,7 +127,7 @@ int getEntitiesTag(TagCompound* chunkRoot,Tag** entities) { TagCompound* level = t->payload; for(int i = 0; i < level->numTags; ++i) { t = &(level->list[i]); - if(!strcmp(t->name,"Entities")) { + if(!strncmp(t->name,"Entities",t->nameLength)) { found = 1; *entities = t; break; @@ -144,13 +155,13 @@ int searchForPet(Tag entities, const char* petName, const char* ownerUUID, Tag** entity = t->payload; for(int j = 0; j < entity->numTags; ++j) { Tag* attr = &(entity->list[j]); - if(!strcmp(attr->name,"OwnerUUID") && ownerUUID != NULL) { - if(!strcmp(attr->payload,ownerUUID)) { + if(!strncmp(attr->name,"OwnerUUID",attr->nameLength) && ownerUUID != NULL) { + if(!strncmp(attr->payload,ownerUUID,attr->payloadLength)) { *pet = t; return 0; } - } else if(!strcmp(attr->name,"CustomName") && petName != NULL) { - if(!strcmp(attr->payload,petName)) { + } else if(!strncmp(attr->name,"CustomName",attr->nameLength) && petName != NULL) { + if(!strncmp(attr->payload,petName,attr->payloadLength)) { *pet = t; return 0; } @@ -201,10 +212,26 @@ ssize_t insertPetIntoChunk(void** chunkData, Tag chunkRoot, Tag* entities, Tag p return chunkDataLength; } +Coords getPetCoords(TagCompound* pet) { + Coords petCoords; + for(int i = 0; i < pet->numTags; ++i) { + Tag* attr = &pet->list[i]; + if(!strncmp(attr->name,"Pos",attr->nameLength)) { + TagList* pos = attr->payload; + petCoords.x = (int)*((double*)pos->list[0].payload); + petCoords.y = (int)*((double*)pos->list[1].payload); + petCoords.z = (int)*((double*)pos->list[2].payload); + } + } + return petCoords; +} + void printHelp() { + fprintf(stderr,"--regiondata ./industrial/world/region --name Iris\n"); + fprintf(stderr,"--regiondata ./industrial/world/region --owner 32812f90-17ec-4f5a-8b7e-e500f17b1ba5\n"); fprintf(stderr,"--regiondata ./industrial/world/region --save Iris.mcdata --name Iris\n"); fprintf(stderr,"--regiondata ./industrial/world/region --save Iris.mcdata --owner 32812f90-17ec-4f5a-8b7e-e500f17b1ba5\n"); - fprintf(stderr,"--regiondata ./industrial/world/region --load Iris.mcdata\n"); + fprintf(stderr,"--regiondata ./industrial/world/region --load Iris.mcdata --coords 801,200,3040\n"); } int main(int argc, char** argv) { @@ -212,7 +239,9 @@ int main(int argc, char** argv) { const char* file = NULL; const char* petName = NULL; const char* ownerUUID = NULL; + const char* coords = NULL; int save = 0; + int load = 0; int longIndex = UNKNOWN; int c; @@ -224,17 +253,15 @@ int main(int argc, char** argv) { return 0; } - while ((c = getopt_long(argc, argv, "r:s:l:n:o:h", longopts, &longIndex)) != -1) + while ((c = getopt_long(argc, argv, "r:s:l:n:o:c:h", longopts, &longIndex)) != -1) { - if(c == 'h') { - printHelp(); - return 0; - } - else if(c == REGION) {regionFolder = optarg;} - else if(c == SAVE) {save = 1;file = optarg;} - else if(c == LOAD) {file = optarg;} - else if(c == NAME) {petName = optarg;} - else if(c == OWNER) {ownerUUID = optarg;} + if(c == HELP || c == 'h') {printHelp();return 0;} + else if(c == REGION || c == 'r') {regionFolder = optarg;} + else if(c == SAVE || c == 's') {save = 1; file = optarg;} + else if(c == LOAD || c == 'l') {load = 1; file = optarg;} + else if(c == NAME || c == 'n') {petName = optarg;} + else if(c == OWNER || c == 'o') {ownerUUID = optarg;} + else if(c == COORDS || c == 'c') {coords = optarg;} else { fprintf(stderr,"Unrecognised argument: %s\n",optarg); printHelp(); @@ -251,75 +278,153 @@ int main(int argc, char** argv) { fprintf(stderr,"Region path not specified (--regionpath PATH_TO_REGION_FOLDER)\n"); printHelp(); return 2; - } else if(save && petName == NULL && ownerUUID == NULL) { + } else if(!load && (petName == NULL && ownerUUID == NULL)) { fprintf(stderr,"OwnerUUID and petName were unspecified (--owner UUID, --name PET_NAME)\n"); printHelp(); return 3; - } else if(!save && (petName != NULL || ownerUUID != NULL)) { - fprintf(stderr,"OwnerUUID and petName were unspecified (--owner UUID, --name PET_NAME)\n"); + } else if(load && (petName != NULL || ownerUUID != NULL)) { + fprintf(stderr,"OwnerUUID and petName options don't apply when loading a pet\n"); printHelp(); return 3; - } else if(file == NULL) { - fprintf(stderr,"Neither saving or loading a pet was requested (--save PATH_TO_FILE, --load PATH_TO_FILE)\n"); + } else if(save && coords == NULL) { + fprintf(stderr,"Coordinates were not specified\n"); printHelp(); return 4; - } + } - void *chunkData; - ChunkID chunk = translateCoordsToChunk(800, 200, 3041); - ssize_t chunkLen = loadChunk(regionFolder, chunk, &chunkData); - if(chunkLen <= 0) { - return chunkLen; - } + if(!load) { + DIR *dirp; + struct dirent *dp; - Tag t; - unsigned int pos = parseTag(chunkData,&t); - if(pos != chunkLen) { - fprintf(stderr, "Didn't reach end of NBT file\n"); - free(chunkData); - return 5; - } + if((dirp = opendir(regionFolder)) == NULL) { + fprintf(stderr,"Unable to open region folder '%s'\n",regionFolder); + return 1; + } - Tag* entities; - if(getEntitiesTag((TagCompound*)t.payload,&entities)) { - fprintf(stderr, "Unable to find Entities tag\n"); - free(chunkData); - return 6; - } - if(save) { - Tag* pet; - if(searchForPet(*entities,petName,ownerUUID,&pet)) { - fprintf(stderr, "Unable to find pet named %s\n",petName); + do { + if((dp = readdir(dirp)) != NULL) { + const char* regionFile = dp->d_name; + RegionID region; + + if(sscanf(regionFile,"r.%d.%d.mca",®ion.x,®ion.z) != 2) { + // WTF? Ignore this file + continue; + } + for(int i = 0; i < CHUNKS_PER_REGION; ++i) { + for(int j = 0; j < CHUNKS_PER_REGION; ++j) { + ChunkID chunk; + chunk.x = i + region.x * CHUNKS_PER_REGION; + chunk.z = j + region.z * CHUNKS_PER_REGION; + + void* chunkData; + printf("Looking in chunk (%d,%d): X (%d -> %d), Z (%d -> %d)\n", + chunk.x, + chunk.z, + chunk.x * BLOCKS_PER_CHUNK, + (chunk.x + 1) * BLOCKS_PER_CHUNK, + chunk.z * BLOCKS_PER_CHUNK, + (chunk.z + 1) * BLOCKS_PER_CHUNK + ); + ssize_t chunkLen = loadChunk(regionFolder, chunk, &chunkData); + if(chunkLen < 0) { + fprintf(stderr, "Unable to load chunk\n"); + return 5; + } else if(chunkLen != 0) { + Tag t; + unsigned int pos = parseTag(chunkData,&t); + if(pos != chunkLen) { + fprintf(stderr, "Didn't reach end of NBT file\n"); + free(chunkData); + return 5; + } + + Tag* entities; + if(getEntitiesTag((TagCompound*)t.payload,&entities)) { + fprintf(stderr, "Unable to find Entities tag\n"); + free(chunkData); + destroyTag(&t); + return 6; + } + Tag* pet; + if(searchForPet(*entities,petName,ownerUUID,&pet) == 0) { + Coords petPosition = getPetCoords(pet->payload); + printf("Found pet! @ (%d,%d,%d)\n",petPosition.x,petPosition.y,petPosition.z); + if(save) { + if(savePetToFile(pet,file)) { + fprintf(stderr, "Unable to save pet to file: %s\n",file); + free(chunkData); + closedir(dirp); + return 8; + } + } + destroyTag(&t); + closedir(dirp); + free(chunkData); + return 0; + } + destroyTag(&t); + free(chunkData); + } + } + } + } + } while (dp != NULL); + printf("Unable to find pet in this world :(\n"); + closedir(dirp); + return 1; + } else { + Coords location; + if(sscanf(coords,"%d,%d,%d",&location.x,&location.y,&location.z) != 3) { + fprintf(stderr, "Unable to parse coordinates, please specify coordinates correctly (--coords X,Y,Z)\n"); + return 5; + } + + void *chunkData; + ChunkID chunk = translateCoordsToChunk(location.x, location.y, location.z); + ssize_t chunkLen = loadChunk(regionFolder, chunk, &chunkData); + if(chunkLen <= 0) { + fprintf(stderr, "Unable to load chunk\n"); + return 5; + } + + Tag t; + unsigned int pos = parseTag(chunkData,&t); + if(pos != chunkLen) { + fprintf(stderr, "Didn't reach end of NBT file\n"); free(chunkData); - return 7; + return 5; } - if(savePetToFile(pet,file)) { - fprintf(stderr, "Unable to save pet to file: %s\n",file); + + Tag* entities; + if(getEntitiesTag((TagCompound*)t.payload,&entities)) { + fprintf(stderr, "Unable to find Entities tag\n"); free(chunkData); - return 8; + destroyTag(&t); + return 6; } - } else { Tag pet; if(loadPetFromFile(&pet,file)) { fprintf(stderr, "Unable to load pet from file: %s\n",file); free(chunkData); + destroyTag(&t); return 9; } - chunkLen = insertPetIntoChunk(&chunkData,t,entities,pet,801,200,3040); + chunkLen = insertPetIntoChunk(&chunkData,t,entities,pet,location.x,location.y,location.z); if(chunkLen <= 0) { fprintf(stderr, "Unable to insert pet into chunk\n"); free(chunkData); + destroyTag(&t); return 10; } destroyTag(&pet); if(overwriteChunk(regionFolder, chunk, chunkData, chunkLen)) { fprintf(stderr, "Unable to write new chunk\n"); free(chunkData); + destroyTag(&t); return 11; } + destroyTag(&t); + free(chunkData); } - - destroyTag(&t); - free(chunkData); return 0; } \ No newline at end of file