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 | 1 | #include <stdio.h> |
2 | 2 | #include <getopt.h> |
3 | +#include <dirent.h> | |
3 | 4 | |
4 | 5 | #include "nbt.h" |
5 | 6 | #include "chunk.h" |
... | ... | @@ -7,19 +8,29 @@ |
7 | 8 | enum paramIndex |
8 | 9 | { |
9 | 10 | UNKNOWN = 0, |
11 | + HELP, | |
10 | 12 | REGION, |
11 | 13 | SAVE, |
12 | 14 | LOAD, |
13 | 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 | 26 | static struct option longopts[] = { |
27 | + { "help", no_argument, NULL, HELP }, | |
18 | 28 | { "regiondata", required_argument, NULL, REGION }, |
19 | 29 | { "save", required_argument, NULL, SAVE }, |
20 | 30 | { "load", required_argument, NULL, LOAD }, |
21 | 31 | { "name", required_argument, NULL, NAME }, |
22 | 32 | { "owner", required_argument, NULL, OWNER }, |
33 | + { "coords", required_argument, NULL, COORDS }, | |
23 | 34 | { NULL, 0, NULL, UNKNOWN } |
24 | 35 | }; |
25 | 36 | |
... | ... | @@ -102,7 +113,7 @@ int getEntitiesTag(TagCompound* chunkRoot,Tag** entities) { |
102 | 113 | int found = 0; |
103 | 114 | for(int i = 0; i < chunkRoot->numTags; ++i) { |
104 | 115 | t = &(chunkRoot->list[i]); |
105 | - if(!strcmp(t->name,"Level")) { | |
116 | + if(!strncmp(t->name,"Level",t->nameLength)) { | |
106 | 117 | found = 1; |
107 | 118 | break; |
108 | 119 | } |
... | ... | @@ -116,7 +127,7 @@ int getEntitiesTag(TagCompound* chunkRoot,Tag** entities) { |
116 | 127 | TagCompound* level = t->payload; |
117 | 128 | for(int i = 0; i < level->numTags; ++i) { |
118 | 129 | t = &(level->list[i]); |
119 | - if(!strcmp(t->name,"Entities")) { | |
130 | + if(!strncmp(t->name,"Entities",t->nameLength)) { | |
120 | 131 | found = 1; |
121 | 132 | *entities = t; |
122 | 133 | break; |
... | ... | @@ -144,13 +155,13 @@ int searchForPet(Tag entities, const char* petName, const char* ownerUUID, Tag** |
144 | 155 | entity = t->payload; |
145 | 156 | for(int j = 0; j < entity->numTags; ++j) { |
146 | 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 | 160 | *pet = t; |
150 | 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 | 165 | *pet = t; |
155 | 166 | return 0; |
156 | 167 | } |
... | ... | @@ -201,10 +212,26 @@ ssize_t insertPetIntoChunk(void** chunkData, Tag chunkRoot, Tag* entities, Tag p |
201 | 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 | 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 | 232 | fprintf(stderr,"--regiondata ./industrial/world/region --save Iris.mcdata --name Iris\n"); |
206 | 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 | 237 | int main(int argc, char** argv) { |
... | ... | @@ -212,7 +239,9 @@ int main(int argc, char** argv) { |
212 | 239 | const char* file = NULL; |
213 | 240 | const char* petName = NULL; |
214 | 241 | const char* ownerUUID = NULL; |
242 | + const char* coords = NULL; | |
215 | 243 | int save = 0; |
244 | + int load = 0; | |
216 | 245 | |
217 | 246 | int longIndex = UNKNOWN; |
218 | 247 | int c; |
... | ... | @@ -224,17 +253,15 @@ int main(int argc, char** argv) { |
224 | 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 | 265 | else { |
239 | 266 | fprintf(stderr,"Unrecognised argument: %s\n",optarg); |
240 | 267 | printHelp(); |
... | ... | @@ -251,75 +278,153 @@ int main(int argc, char** argv) { |
251 | 278 | fprintf(stderr,"Region path not specified (--regionpath PATH_TO_REGION_FOLDER)\n"); |
252 | 279 | printHelp(); |
253 | 280 | return 2; |
254 | - } else if(save && petName == NULL && ownerUUID == NULL) { | |
281 | + } else if(!load && (petName == NULL && ownerUUID == NULL)) { | |
255 | 282 | fprintf(stderr,"OwnerUUID and petName were unspecified (--owner UUID, --name PET_NAME)\n"); |
256 | 283 | printHelp(); |
257 | 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 | 287 | printHelp(); |
261 | 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 | 291 | printHelp(); |
265 | 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 | 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 | 401 | free(chunkData); |
299 | - return 8; | |
402 | + destroyTag(&t); | |
403 | + return 6; | |
300 | 404 | } |
301 | - } else { | |
302 | 405 | Tag pet; |
303 | 406 | if(loadPetFromFile(&pet,file)) { |
304 | 407 | fprintf(stderr, "Unable to load pet from file: %s\n",file); |
305 | 408 | free(chunkData); |
409 | + destroyTag(&t); | |
306 | 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 | 413 | if(chunkLen <= 0) { |
310 | 414 | fprintf(stderr, "Unable to insert pet into chunk\n"); |
311 | 415 | free(chunkData); |
416 | + destroyTag(&t); | |
312 | 417 | return 10; |
313 | 418 | } |
314 | 419 | destroyTag(&pet); |
315 | 420 | if(overwriteChunk(regionFolder, chunk, chunkData, chunkLen)) { |
316 | 421 | fprintf(stderr, "Unable to write new chunk\n"); |
317 | 422 | free(chunkData); |
423 | + destroyTag(&t); | |
318 | 424 | return 11; |
319 | 425 | } |
426 | + destroyTag(&t); | |
427 | + free(chunkData); | |
320 | 428 | } |
321 | - | |
322 | - destroyTag(&t); | |
323 | - free(chunkData); | |
324 | 429 | return 0; |
325 | 430 | } |
326 | 431 | \ No newline at end of file | ... | ... |