Commit ab8cd4ec023b1eb75803ecd209d6039680cc1169
0 parents
Initial import. Incomplete version without getopt implementation
Showing
1 changed file
with
253 additions
and
0 deletions
mcpetbackup.c
0 → 100644
1 | +++ a/mcpetbackup.c | ||
1 | +#include <stdio.h> | ||
2 | + | ||
3 | +#include "nbt.h" | ||
4 | +#include "chunk.h" | ||
5 | + | ||
6 | +int savePetToFile(Tag* pet, const char* filename) { | ||
7 | + void* petData; | ||
8 | + size_t petDataLength = composeTag(*pet, &petData); | ||
9 | + | ||
10 | + int fd = open(filename,O_CREAT|O_WRONLY,0644); | ||
11 | + if(fd == -1) { | ||
12 | + fprintf(stderr,"Unable to open file to save pet: %s\n",strerror(errno)); | ||
13 | + free(petData); | ||
14 | + return 1; | ||
15 | + } | ||
16 | + ssize_t nWritten = 0; | ||
17 | + size_t totalWritten = 0; | ||
18 | + | ||
19 | + while((nWritten = write(fd,petData+totalWritten,petDataLength-totalWritten))) { | ||
20 | + if(nWritten == -1) { | ||
21 | + if(errno == EINTR) { | ||
22 | + continue; | ||
23 | + } | ||
24 | + fprintf(stderr,"Unable to write pet data: %s\n",strerror(errno)); | ||
25 | + close(fd); | ||
26 | + free(petData); | ||
27 | + return 2; | ||
28 | + } | ||
29 | + totalWritten += nWritten; | ||
30 | + } | ||
31 | + close(fd); | ||
32 | + | ||
33 | + free(petData); | ||
34 | + return 0; | ||
35 | +} | ||
36 | + | ||
37 | +int loadPetFromFile(Tag* pet, const char* filename) { | ||
38 | + int fd = open(filename,O_RDONLY); | ||
39 | + if(fd == -1) { | ||
40 | + fprintf(stderr,"Unable to open file to load pet: %s\n",strerror(errno)); | ||
41 | + return 1; | ||
42 | + } | ||
43 | + | ||
44 | + struct stat sb; | ||
45 | + if(stat(filename,&sb) == -1) { | ||
46 | + fprintf(stderr,"Unable to stat() file to load pet: %s\n",strerror(errno)); | ||
47 | + close(fd); | ||
48 | + return 2; | ||
49 | + } | ||
50 | + void* petData = calloc(sb.st_size,sizeof(uint8_t)); | ||
51 | + | ||
52 | + ssize_t nRead = 0; | ||
53 | + size_t totalRead = 0; | ||
54 | + | ||
55 | + while((nRead = read(fd,petData+totalRead,sb.st_size-totalRead))) { | ||
56 | + if(nRead == -1) { | ||
57 | + if(errno == EINTR) { | ||
58 | + continue; | ||
59 | + } | ||
60 | + fprintf(stderr,"Unable to write pet data: %s\n",strerror(errno)); | ||
61 | + close(fd); | ||
62 | + free(petData); | ||
63 | + return 3; | ||
64 | + } | ||
65 | + totalRead += nRead; | ||
66 | + } | ||
67 | + close(fd); | ||
68 | + | ||
69 | + size_t pos = parseTag(petData,pet); | ||
70 | + if(pos != sb.st_size) { | ||
71 | + fprintf(stderr,"Error parsing pet data\n"); | ||
72 | + free(petData); | ||
73 | + return 4; | ||
74 | + } | ||
75 | + | ||
76 | + free(petData); | ||
77 | + return 0; | ||
78 | +} | ||
79 | + | ||
80 | +int getEntitiesTag(TagCompound* chunkRoot,Tag** entities) { | ||
81 | + Tag* t; | ||
82 | + int found = 0; | ||
83 | + for(int i = 0; i < chunkRoot->numTags; ++i) { | ||
84 | + t = &(chunkRoot->list[i]); | ||
85 | + if(!strcmp(t->name,"Level")) { | ||
86 | + found = 1; | ||
87 | + break; | ||
88 | + } | ||
89 | + } | ||
90 | + if(!found) { | ||
91 | + fprintf(stderr,"Unable to locate Level tag\n"); | ||
92 | + return 1; | ||
93 | + } | ||
94 | + found = 0; | ||
95 | + | ||
96 | + TagCompound* level = t->payload; | ||
97 | + for(int i = 0; i < level->numTags; ++i) { | ||
98 | + t = &(level->list[i]); | ||
99 | + if(!strcmp(t->name,"Entities")) { | ||
100 | + found = 1; | ||
101 | + *entities = t; | ||
102 | + break; | ||
103 | + } | ||
104 | + } | ||
105 | + if(!found) { | ||
106 | + fprintf(stderr,"Unable to locate Entities tag\n"); | ||
107 | + return 2; | ||
108 | + } | ||
109 | + *entities = t; | ||
110 | + return 0; | ||
111 | +} | ||
112 | + | ||
113 | +int searchForPet(Tag entities, const char* petName, const char* ownerUUID, Tag** pet) { | ||
114 | + if(petName == NULL && ownerUUID == NULL) { | ||
115 | + fprintf(stderr,"At least petName or ownerUUID have to be non-NULL\n"); | ||
116 | + return -1; | ||
117 | + } | ||
118 | + | ||
119 | + Tag* t; | ||
120 | + TagList* entitiesList = entities.payload; | ||
121 | + TagCompound* entity; | ||
122 | + for(int i = 0; i < entitiesList->size; ++i) { | ||
123 | + t = &(entitiesList->list[i]); | ||
124 | + entity = t->payload; | ||
125 | + for(int j = 0; j < entity->numTags; ++j) { | ||
126 | + Tag* attr = &(entity->list[j]); | ||
127 | + if(!strcmp(attr->name,"OwnerUUID") && ownerUUID != NULL) { | ||
128 | + if(!strcmp(attr->payload,ownerUUID)) { | ||
129 | + *pet = t; | ||
130 | + return 0; | ||
131 | + } | ||
132 | + } else if(!strcmp(attr->name,"CustomName") && petName != NULL) { | ||
133 | + if(!strcmp(attr->payload,petName)) { | ||
134 | + *pet = t; | ||
135 | + return 0; | ||
136 | + } | ||
137 | + } | ||
138 | + } | ||
139 | + } | ||
140 | + return 1; | ||
141 | +} | ||
142 | + | ||
143 | +ssize_t insertPetIntoChunk(void** chunkData, Tag chunkRoot, Tag* entities, Tag pet, double x, double y, double z) { | ||
144 | + TagList* entitiesList = (TagList*)entities->payload; | ||
145 | + if(entitiesList->type == TAG_END) { | ||
146 | + // Entities was an empty list. Generating it | ||
147 | + entitiesList->type = TAG_COMPOUND; | ||
148 | + entitiesList->size = 0; | ||
149 | + entitiesList->list = calloc(1,sizeof(uint8_t)); | ||
150 | + } | ||
151 | + void* newptr = reallocarray(entitiesList->list,++entitiesList->size,sizeof(Tag)); | ||
152 | + if(newptr == NULL) { | ||
153 | + fprintf(stderr,"Unable to realloc an additional entity on the entities list\n"); | ||
154 | + return -1; | ||
155 | + } | ||
156 | + entitiesList->list = newptr; | ||
157 | + Tag* newPet = &entitiesList->list[(entitiesList->size) - 1]; | ||
158 | + | ||
159 | + void* rawPetData; | ||
160 | + size_t rawPetDataLength = composeTag(pet,&rawPetData); | ||
161 | + size_t parsePos = parseTag(rawPetData,newPet); | ||
162 | + if(parsePos != rawPetDataLength) { | ||
163 | + fprintf(stderr,"Error while duplicating pet. New pet data does not match original\n"); | ||
164 | + free(rawPetData); | ||
165 | + return -2; | ||
166 | + } | ||
167 | + free(rawPetData); | ||
168 | + | ||
169 | + void* newChunkData; | ||
170 | + size_t chunkDataLength = composeTag(chunkRoot, &newChunkData); | ||
171 | + newptr = realloc(*chunkData,chunkDataLength); | ||
172 | + if(newptr == NULL) { | ||
173 | + fprintf(stderr,"Unable to realloc chunkData to fit new data\n"); | ||
174 | + free(newChunkData); | ||
175 | + return -4; | ||
176 | + } | ||
177 | + *chunkData = newptr; | ||
178 | + memcpy(*chunkData,newChunkData,chunkDataLength); | ||
179 | + free(newChunkData); | ||
180 | + | ||
181 | + return chunkDataLength; | ||
182 | +} | ||
183 | + | ||
184 | +int main(int argc, char** argv) { | ||
185 | + // TODO argv | ||
186 | + // --regiondata ./industrial/world/region --save Iris.mcdata --name Iris | ||
187 | + // --regiondata ./industrial/world/region --save Iris.mcdata --owner 32812f90-17ec-4f5a-8b7e-e500f17b1ba5 | ||
188 | + // --regiondata ./industrial/world/region --load Iris.mcdata | ||
189 | + | ||
190 | + const char* regionFolder = "./industrial/world/region"; | ||
191 | + const char* petName = "Iris"; | ||
192 | + int save = 0; | ||
193 | + const char* outputFile = "Iris.mcdata"; | ||
194 | + const char* inputFile = "Iris.mcdata"; | ||
195 | + | ||
196 | + void *chunkData; | ||
197 | + ChunkID chunk = translateCoordsToChunk(800, 200, 3041); | ||
198 | + ssize_t chunkLen = loadChunk(regionFolder, chunk, &chunkData); | ||
199 | + if(chunkLen <= 0) { | ||
200 | + return chunkLen; | ||
201 | + } | ||
202 | + | ||
203 | + Tag t; | ||
204 | + unsigned int pos = parseTag(chunkData,&t); | ||
205 | + if(pos != chunkLen) { | ||
206 | + fprintf(stderr, "Didn't reach end of NBT file\n"); | ||
207 | + free(chunkData); | ||
208 | + return 1; | ||
209 | + } | ||
210 | + | ||
211 | + Tag* entities; | ||
212 | + if(getEntitiesTag((TagCompound*)t.payload,&entities)) { | ||
213 | + fprintf(stderr, "Unable to find Entities tag\n"); | ||
214 | + free(chunkData); | ||
215 | + return 2; | ||
216 | + } | ||
217 | + if(save) { | ||
218 | + Tag* pet; | ||
219 | + if(searchForPet(*entities,petName,NULL,&pet)) { | ||
220 | + fprintf(stderr, "Unable to find pet named %s\n",petName); | ||
221 | + free(chunkData); | ||
222 | + return 3; | ||
223 | + } | ||
224 | + if(savePetToFile(pet,outputFile)) { | ||
225 | + fprintf(stderr, "Unable to save pet to file: %s\n",outputFile); | ||
226 | + free(chunkData); | ||
227 | + return 4; | ||
228 | + } | ||
229 | + } else { | ||
230 | + Tag pet; | ||
231 | + if(loadPetFromFile(&pet,inputFile)) { | ||
232 | + fprintf(stderr, "Unable to load pet from file: %s\n",inputFile); | ||
233 | + free(chunkData); | ||
234 | + return 5; | ||
235 | + } | ||
236 | + chunkLen = insertPetIntoChunk(&chunkData,t,entities,pet,801,200,3040); | ||
237 | + if(chunkLen <= 0) { | ||
238 | + fprintf(stderr, "Unable to insert pet into chunk\n"); | ||
239 | + free(chunkData); | ||
240 | + return 6; | ||
241 | + } | ||
242 | + destroyTag(&pet); | ||
243 | + if(overwriteChunk(regionFolder, chunk, chunkData, chunkLen)) { | ||
244 | + fprintf(stderr, "Unable to write new chunk\n"); | ||
245 | + free(chunkData); | ||
246 | + return 7; | ||
247 | + } | ||
248 | + } | ||
249 | + | ||
250 | + destroyTag(&t); | ||
251 | + free(chunkData); | ||
252 | + return 0; | ||
253 | +} | ||
0 | \ No newline at end of file | 254 | \ No newline at end of file |