Commit 1e868e43415a97f5d24ed6997028260b52adde17
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",®ion.x,®ion.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 |