Commit 1e868e43415a97f5d24ed6997028260b52adde17

Authored by Imanol-Mikel Barba Sabariego
1 parent 6a6d7496

Fully implemented all options. Fixed several memory errors

Showing 1 changed file with 161 additions and 56 deletions
mcpetbackup.c
1 #include <stdio.h> 1 #include <stdio.h>
2 #include <getopt.h> 2 #include <getopt.h>
  3 +#include <dirent.h>
3 4
4 #include "nbt.h" 5 #include "nbt.h"
5 #include "chunk.h" 6 #include "chunk.h"
@@ -7,19 +8,29 @@ @@ -7,19 +8,29 @@
7 enum paramIndex 8 enum paramIndex
8 { 9 {
9 UNKNOWN = 0, 10 UNKNOWN = 0,
  11 + HELP,
10 REGION, 12 REGION,
11 SAVE, 13 SAVE,
12 LOAD, 14 LOAD,
13 NAME, 15 NAME,
14 - OWNER 16 + OWNER,
  17 + COORDS
15 }; 18 };
16 19
  20 +typedef struct Coords {
  21 + int x;
  22 + int y;
  23 + int z;
  24 +} Coords;
  25 +
17 static struct option longopts[] = { 26 static struct option longopts[] = {
  27 + { "help", no_argument, NULL, HELP },
18 { "regiondata", required_argument, NULL, REGION }, 28 { "regiondata", required_argument, NULL, REGION },
19 { "save", required_argument, NULL, SAVE }, 29 { "save", required_argument, NULL, SAVE },
20 { "load", required_argument, NULL, LOAD }, 30 { "load", required_argument, NULL, LOAD },
21 { "name", required_argument, NULL, NAME }, 31 { "name", required_argument, NULL, NAME },
22 { "owner", required_argument, NULL, OWNER }, 32 { "owner", required_argument, NULL, OWNER },
  33 + { "coords", required_argument, NULL, COORDS },
23 { NULL, 0, NULL, UNKNOWN } 34 { NULL, 0, NULL, UNKNOWN }
24 }; 35 };
25 36
@@ -102,7 +113,7 @@ int getEntitiesTag(TagCompound* chunkRoot,Tag** entities) { @@ -102,7 +113,7 @@ int getEntitiesTag(TagCompound* chunkRoot,Tag** entities) {
102 int found = 0; 113 int found = 0;
103 for(int i = 0; i < chunkRoot->numTags; ++i) { 114 for(int i = 0; i < chunkRoot->numTags; ++i) {
104 t = &(chunkRoot->list[i]); 115 t = &(chunkRoot->list[i]);
105 - if(!strcmp(t->name,"Level")) { 116 + if(!strncmp(t->name,"Level",t->nameLength)) {
106 found = 1; 117 found = 1;
107 break; 118 break;
108 } 119 }
@@ -116,7 +127,7 @@ int getEntitiesTag(TagCompound* chunkRoot,Tag** entities) { @@ -116,7 +127,7 @@ int getEntitiesTag(TagCompound* chunkRoot,Tag** entities) {
116 TagCompound* level = t->payload; 127 TagCompound* level = t->payload;
117 for(int i = 0; i < level->numTags; ++i) { 128 for(int i = 0; i < level->numTags; ++i) {
118 t = &(level->list[i]); 129 t = &(level->list[i]);
119 - if(!strcmp(t->name,"Entities")) { 130 + if(!strncmp(t->name,"Entities",t->nameLength)) {
120 found = 1; 131 found = 1;
121 *entities = t; 132 *entities = t;
122 break; 133 break;
@@ -144,13 +155,13 @@ int searchForPet(Tag entities, const char* petName, const char* ownerUUID, Tag** @@ -144,13 +155,13 @@ int searchForPet(Tag entities, const char* petName, const char* ownerUUID, Tag**
144 entity = t->payload; 155 entity = t->payload;
145 for(int j = 0; j < entity->numTags; ++j) { 156 for(int j = 0; j < entity->numTags; ++j) {
146 Tag* attr = &(entity->list[j]); 157 Tag* attr = &(entity->list[j]);
147 - if(!strcmp(attr->name,"OwnerUUID") && ownerUUID != NULL) {  
148 - if(!strcmp(attr->payload,ownerUUID)) { 158 + if(!strncmp(attr->name,"OwnerUUID",attr->nameLength) && ownerUUID != NULL) {
  159 + if(!strncmp(attr->payload,ownerUUID,attr->payloadLength)) {
149 *pet = t; 160 *pet = t;
150 return 0; 161 return 0;
151 } 162 }
152 - } else if(!strcmp(attr->name,"CustomName") && petName != NULL) {  
153 - if(!strcmp(attr->payload,petName)) { 163 + } else if(!strncmp(attr->name,"CustomName",attr->nameLength) && petName != NULL) {
  164 + if(!strncmp(attr->payload,petName,attr->payloadLength)) {
154 *pet = t; 165 *pet = t;
155 return 0; 166 return 0;
156 } 167 }
@@ -201,10 +212,26 @@ ssize_t insertPetIntoChunk(void** chunkData, Tag chunkRoot, Tag* entities, Tag p @@ -201,10 +212,26 @@ ssize_t insertPetIntoChunk(void** chunkData, Tag chunkRoot, Tag* entities, Tag p
201 return chunkDataLength; 212 return chunkDataLength;
202 } 213 }
203 214
  215 +Coords getPetCoords(TagCompound* pet) {
  216 + Coords petCoords;
  217 + for(int i = 0; i < pet->numTags; ++i) {
  218 + Tag* attr = &pet->list[i];
  219 + if(!strncmp(attr->name,"Pos",attr->nameLength)) {
  220 + TagList* pos = attr->payload;
  221 + petCoords.x = (int)*((double*)pos->list[0].payload);
  222 + petCoords.y = (int)*((double*)pos->list[1].payload);
  223 + petCoords.z = (int)*((double*)pos->list[2].payload);
  224 + }
  225 + }
  226 + return petCoords;
  227 +}
  228 +
204 void printHelp() { 229 void printHelp() {
  230 + fprintf(stderr,"--regiondata ./industrial/world/region --name Iris\n");
  231 + fprintf(stderr,"--regiondata ./industrial/world/region --owner 32812f90-17ec-4f5a-8b7e-e500f17b1ba5\n");
205 fprintf(stderr,"--regiondata ./industrial/world/region --save Iris.mcdata --name Iris\n"); 232 fprintf(stderr,"--regiondata ./industrial/world/region --save Iris.mcdata --name Iris\n");
206 fprintf(stderr,"--regiondata ./industrial/world/region --save Iris.mcdata --owner 32812f90-17ec-4f5a-8b7e-e500f17b1ba5\n"); 233 fprintf(stderr,"--regiondata ./industrial/world/region --save Iris.mcdata --owner 32812f90-17ec-4f5a-8b7e-e500f17b1ba5\n");
207 - fprintf(stderr,"--regiondata ./industrial/world/region --load Iris.mcdata\n"); 234 + fprintf(stderr,"--regiondata ./industrial/world/region --load Iris.mcdata --coords 801,200,3040\n");
208 } 235 }
209 236
210 int main(int argc, char** argv) { 237 int main(int argc, char** argv) {
@@ -212,7 +239,9 @@ int main(int argc, char** argv) { @@ -212,7 +239,9 @@ int main(int argc, char** argv) {
212 const char* file = NULL; 239 const char* file = NULL;
213 const char* petName = NULL; 240 const char* petName = NULL;
214 const char* ownerUUID = NULL; 241 const char* ownerUUID = NULL;
  242 + const char* coords = NULL;
215 int save = 0; 243 int save = 0;
  244 + int load = 0;
216 245
217 int longIndex = UNKNOWN; 246 int longIndex = UNKNOWN;
218 int c; 247 int c;
@@ -224,17 +253,15 @@ int main(int argc, char** argv) { @@ -224,17 +253,15 @@ int main(int argc, char** argv) {
224 return 0; 253 return 0;
225 } 254 }
226 255
227 - while ((c = getopt_long(argc, argv, "r:s:l:n:o:h", longopts, &longIndex)) != -1) 256 + while ((c = getopt_long(argc, argv, "r:s:l:n:o:c:h", longopts, &longIndex)) != -1)
228 { 257 {
229 - if(c == 'h') {  
230 - printHelp();  
231 - return 0;  
232 - }  
233 - else if(c == REGION) {regionFolder = optarg;}  
234 - else if(c == SAVE) {save = 1;file = optarg;}  
235 - else if(c == LOAD) {file = optarg;}  
236 - else if(c == NAME) {petName = optarg;}  
237 - else if(c == OWNER) {ownerUUID = optarg;} 258 + if(c == HELP || c == 'h') {printHelp();return 0;}
  259 + else if(c == REGION || c == 'r') {regionFolder = optarg;}
  260 + else if(c == SAVE || c == 's') {save = 1; file = optarg;}
  261 + else if(c == LOAD || c == 'l') {load = 1; file = optarg;}
  262 + else if(c == NAME || c == 'n') {petName = optarg;}
  263 + else if(c == OWNER || c == 'o') {ownerUUID = optarg;}
  264 + else if(c == COORDS || c == 'c') {coords = optarg;}
238 else { 265 else {
239 fprintf(stderr,"Unrecognised argument: %s\n",optarg); 266 fprintf(stderr,"Unrecognised argument: %s\n",optarg);
240 printHelp(); 267 printHelp();
@@ -251,75 +278,153 @@ int main(int argc, char** argv) { @@ -251,75 +278,153 @@ int main(int argc, char** argv) {
251 fprintf(stderr,"Region path not specified (--regionpath PATH_TO_REGION_FOLDER)\n"); 278 fprintf(stderr,"Region path not specified (--regionpath PATH_TO_REGION_FOLDER)\n");
252 printHelp(); 279 printHelp();
253 return 2; 280 return 2;
254 - } else if(save && petName == NULL && ownerUUID == NULL) { 281 + } else if(!load && (petName == NULL && ownerUUID == NULL)) {
255 fprintf(stderr,"OwnerUUID and petName were unspecified (--owner UUID, --name PET_NAME)\n"); 282 fprintf(stderr,"OwnerUUID and petName were unspecified (--owner UUID, --name PET_NAME)\n");
256 printHelp(); 283 printHelp();
257 return 3; 284 return 3;
258 - } else if(!save && (petName != NULL || ownerUUID != NULL)) {  
259 - fprintf(stderr,"OwnerUUID and petName were unspecified (--owner UUID, --name PET_NAME)\n"); 285 + } else if(load && (petName != NULL || ownerUUID != NULL)) {
  286 + fprintf(stderr,"OwnerUUID and petName options don't apply when loading a pet\n");
260 printHelp(); 287 printHelp();
261 return 3; 288 return 3;
262 - } else if(file == NULL) {  
263 - fprintf(stderr,"Neither saving or loading a pet was requested (--save PATH_TO_FILE, --load PATH_TO_FILE)\n"); 289 + } else if(save && coords == NULL) {
  290 + fprintf(stderr,"Coordinates were not specified\n");
264 printHelp(); 291 printHelp();
265 return 4; 292 return 4;
266 - } 293 + }
267 294
268 - void *chunkData;  
269 - ChunkID chunk = translateCoordsToChunk(800, 200, 3041);  
270 - ssize_t chunkLen = loadChunk(regionFolder, chunk, &chunkData);  
271 - if(chunkLen <= 0) {  
272 - return chunkLen;  
273 - } 295 + if(!load) {
  296 + DIR *dirp;
  297 + struct dirent *dp;
274 298
275 - Tag t;  
276 - unsigned int pos = parseTag(chunkData,&t);  
277 - if(pos != chunkLen) {  
278 - fprintf(stderr, "Didn't reach end of NBT file\n");  
279 - free(chunkData);  
280 - return 5;  
281 - } 299 + if((dirp = opendir(regionFolder)) == NULL) {
  300 + fprintf(stderr,"Unable to open region folder '%s'\n",regionFolder);
  301 + return 1;
  302 + }
282 303
283 - Tag* entities;  
284 - if(getEntitiesTag((TagCompound*)t.payload,&entities)) {  
285 - fprintf(stderr, "Unable to find Entities tag\n");  
286 - free(chunkData);  
287 - return 6;  
288 - }  
289 - if(save) {  
290 - Tag* pet;  
291 - if(searchForPet(*entities,petName,ownerUUID,&pet)) {  
292 - fprintf(stderr, "Unable to find pet named %s\n",petName); 304 + do {
  305 + if((dp = readdir(dirp)) != NULL) {
  306 + const char* regionFile = dp->d_name;
  307 + RegionID region;
  308 +
  309 + if(sscanf(regionFile,"r.%d.%d.mca",&region.x,&region.z) != 2) {
  310 + // WTF? Ignore this file
  311 + continue;
  312 + }
  313 + for(int i = 0; i < CHUNKS_PER_REGION; ++i) {
  314 + for(int j = 0; j < CHUNKS_PER_REGION; ++j) {
  315 + ChunkID chunk;
  316 + chunk.x = i + region.x * CHUNKS_PER_REGION;
  317 + chunk.z = j + region.z * CHUNKS_PER_REGION;
  318 +
  319 + void* chunkData;
  320 + printf("Looking in chunk (%d,%d): X (%d -> %d), Z (%d -> %d)\n",
  321 + chunk.x,
  322 + chunk.z,
  323 + chunk.x * BLOCKS_PER_CHUNK,
  324 + (chunk.x + 1) * BLOCKS_PER_CHUNK,
  325 + chunk.z * BLOCKS_PER_CHUNK,
  326 + (chunk.z + 1) * BLOCKS_PER_CHUNK
  327 + );
  328 + ssize_t chunkLen = loadChunk(regionFolder, chunk, &chunkData);
  329 + if(chunkLen < 0) {
  330 + fprintf(stderr, "Unable to load chunk\n");
  331 + return 5;
  332 + } else if(chunkLen != 0) {
  333 + Tag t;
  334 + unsigned int pos = parseTag(chunkData,&t);
  335 + if(pos != chunkLen) {
  336 + fprintf(stderr, "Didn't reach end of NBT file\n");
  337 + free(chunkData);
  338 + return 5;
  339 + }
  340 +
  341 + Tag* entities;
  342 + if(getEntitiesTag((TagCompound*)t.payload,&entities)) {
  343 + fprintf(stderr, "Unable to find Entities tag\n");
  344 + free(chunkData);
  345 + destroyTag(&t);
  346 + return 6;
  347 + }
  348 + Tag* pet;
  349 + if(searchForPet(*entities,petName,ownerUUID,&pet) == 0) {
  350 + Coords petPosition = getPetCoords(pet->payload);
  351 + printf("Found pet! @ (%d,%d,%d)\n",petPosition.x,petPosition.y,petPosition.z);
  352 + if(save) {
  353 + if(savePetToFile(pet,file)) {
  354 + fprintf(stderr, "Unable to save pet to file: %s\n",file);
  355 + free(chunkData);
  356 + closedir(dirp);
  357 + return 8;
  358 + }
  359 + }
  360 + destroyTag(&t);
  361 + closedir(dirp);
  362 + free(chunkData);
  363 + return 0;
  364 + }
  365 + destroyTag(&t);
  366 + free(chunkData);
  367 + }
  368 + }
  369 + }
  370 + }
  371 + } while (dp != NULL);
  372 + printf("Unable to find pet in this world :(\n");
  373 + closedir(dirp);
  374 + return 1;
  375 + } else {
  376 + Coords location;
  377 + if(sscanf(coords,"%d,%d,%d",&location.x,&location.y,&location.z) != 3) {
  378 + fprintf(stderr, "Unable to parse coordinates, please specify coordinates correctly (--coords X,Y,Z)\n");
  379 + return 5;
  380 + }
  381 +
  382 + void *chunkData;
  383 + ChunkID chunk = translateCoordsToChunk(location.x, location.y, location.z);
  384 + ssize_t chunkLen = loadChunk(regionFolder, chunk, &chunkData);
  385 + if(chunkLen <= 0) {
  386 + fprintf(stderr, "Unable to load chunk\n");
  387 + return 5;
  388 + }
  389 +
  390 + Tag t;
  391 + unsigned int pos = parseTag(chunkData,&t);
  392 + if(pos != chunkLen) {
  393 + fprintf(stderr, "Didn't reach end of NBT file\n");
293 free(chunkData); 394 free(chunkData);
294 - return 7; 395 + return 5;
295 } 396 }
296 - if(savePetToFile(pet,file)) {  
297 - fprintf(stderr, "Unable to save pet to file: %s\n",file); 397 +
  398 + Tag* entities;
  399 + if(getEntitiesTag((TagCompound*)t.payload,&entities)) {
  400 + fprintf(stderr, "Unable to find Entities tag\n");
298 free(chunkData); 401 free(chunkData);
299 - return 8; 402 + destroyTag(&t);
  403 + return 6;
300 } 404 }
301 - } else {  
302 Tag pet; 405 Tag pet;
303 if(loadPetFromFile(&pet,file)) { 406 if(loadPetFromFile(&pet,file)) {
304 fprintf(stderr, "Unable to load pet from file: %s\n",file); 407 fprintf(stderr, "Unable to load pet from file: %s\n",file);
305 free(chunkData); 408 free(chunkData);
  409 + destroyTag(&t);
306 return 9; 410 return 9;
307 } 411 }
308 - chunkLen = insertPetIntoChunk(&chunkData,t,entities,pet,801,200,3040); 412 + chunkLen = insertPetIntoChunk(&chunkData,t,entities,pet,location.x,location.y,location.z);
309 if(chunkLen <= 0) { 413 if(chunkLen <= 0) {
310 fprintf(stderr, "Unable to insert pet into chunk\n"); 414 fprintf(stderr, "Unable to insert pet into chunk\n");
311 free(chunkData); 415 free(chunkData);
  416 + destroyTag(&t);
312 return 10; 417 return 10;
313 } 418 }
314 destroyTag(&pet); 419 destroyTag(&pet);
315 if(overwriteChunk(regionFolder, chunk, chunkData, chunkLen)) { 420 if(overwriteChunk(regionFolder, chunk, chunkData, chunkLen)) {
316 fprintf(stderr, "Unable to write new chunk\n"); 421 fprintf(stderr, "Unable to write new chunk\n");
317 free(chunkData); 422 free(chunkData);
  423 + destroyTag(&t);
318 return 11; 424 return 11;
319 } 425 }
  426 + destroyTag(&t);
  427 + free(chunkData);
320 } 428 }
321 -  
322 - destroyTag(&t);  
323 - free(chunkData);  
324 return 0; 429 return 0;
325 } 430 }
326 \ No newline at end of file 431 \ No newline at end of file