6 #define FAST_CHUNK // disabling this enables the old, slower path that deblocks into a regular form
8 #include "cave_parse.h"
10 #include "stb_image.h"
13 #define NUM_CHUNKS_PER_REGION 32 // only on one axis
14 #define NUM_CHUNKS_PER_REGION_LOG2 5
16 #define NUM_COLUMNS_PER_CHUNK 16
17 #define NUM_COLUMNS_PER_CHUNK_LOG2 4
19 uint32
read_uint32_be(FILE *f
)
21 unsigned char data
[4];
23 return (data
[0]<<24) + (data
[1]<<16) + (data
[2]<<8) + data
[3];
30 int x
,z
; // chunk index
31 int refcount
; // for multi-threading
37 uint32 sector_data
[NUM_CHUNKS_PER_REGION
][NUM_CHUNKS_PER_REGION
];
40 size_t cached_compressed
=0;
47 static void open_file(int reg_x
, int reg_z
)
49 if (!opened
|| last_region_x
!= reg_x
|| last_region_z
!= reg_z
) {
51 if (last_region
!= NULL
)
53 sprintf(filename
, "r.%d.%d.mca", reg_x
, reg_z
);
54 last_region
= fopen(filename
, "rb");
55 last_region_x
= reg_x
;
56 last_region_z
= reg_z
;
61 static region
*load_region(int reg_x
, int reg_z
)
66 open_file(reg_x
, reg_z
);
68 r
= malloc(sizeof(*r
));
70 if (last_region
== NULL
) {
71 memset(r
, 0, sizeof(*r
));
73 fseek(last_region
, 0, SEEK_SET
);
74 for (z
=0; z
< NUM_CHUNKS_PER_REGION
; ++z
)
75 for (x
=0; x
< NUM_CHUNKS_PER_REGION
; ++x
)
76 r
->sector_data
[z
][x
] = read_uint32_be(last_region
);
84 void free_region(region
*r
)
89 #define MAX_MAP_REGIONS 64 // in one axis: 64 regions * 32 chunk/region * 16 columns/chunk = 16384 columns
90 region
*regions
[MAX_MAP_REGIONS
][MAX_MAP_REGIONS
];
92 static region
*get_region(int reg_x
, int reg_z
)
94 int slot_x
= reg_x
& (MAX_MAP_REGIONS
-1);
95 int slot_z
= reg_z
& (MAX_MAP_REGIONS
-1);
98 r
= regions
[slot_z
][slot_x
];
101 if (r
->x
== reg_x
&& r
->z
== reg_z
)
106 r
= load_region(reg_x
, reg_z
);
107 regions
[slot_z
][slot_x
] = r
;
112 // about one region, so size should be ok
113 #define NUM_CACHED_X 64
114 #define NUM_CACHED_Z 64
116 // @TODO: is it really worth caching these? we probably can just
117 // pull them from the disk cache nearly as efficiently.
118 // Can test that by setting to 1x1?
119 compressed_chunk
*cached_chunk
[NUM_CACHED_Z
][NUM_CACHED_X
];
121 static void deref_compressed_chunk(compressed_chunk
*cc
)
123 assert(cc
->refcount
> 0);
125 if (cc
->refcount
== 0) {
132 static compressed_chunk
*get_compressed_chunk(int chunk_x
, int chunk_z
)
134 int slot_x
= chunk_x
& (NUM_CACHED_X
-1);
135 int slot_z
= chunk_z
& (NUM_CACHED_Z
-1);
136 compressed_chunk
*cc
= cached_chunk
[slot_z
][slot_x
];
138 if (cc
&& cc
->x
== chunk_x
&& cc
->z
== chunk_z
)
141 int reg_x
= chunk_x
>> NUM_CHUNKS_PER_REGION_LOG2
;
142 int reg_z
= chunk_z
>> NUM_CHUNKS_PER_REGION_LOG2
;
143 region
*r
= get_region(reg_x
, reg_z
);
145 deref_compressed_chunk(cc
);
146 cached_chunk
[slot_z
][slot_x
] = NULL
;
148 cc
= malloc(sizeof(*cc
));
152 int subchunk_x
= chunk_x
& (NUM_CHUNKS_PER_REGION
-1);
153 int subchunk_z
= chunk_z
& (NUM_CHUNKS_PER_REGION
-1);
154 uint32 code
= r
->sector_data
[subchunk_z
][subchunk_x
];
157 open_file(reg_x
, reg_z
);
158 fseek(last_region
, (code
>>8)*4096, SEEK_SET
);
159 cc
->len
= (code
&255)*4096;
160 cc
->data
= malloc(cc
->len
);
161 fread(cc
->data
, 1, cc
->len
, last_region
);
168 cached_chunk
[slot_z
][slot_x
] = cc
;
174 // NBT parser -- can automatically parse stuff we don't
175 // have definitions for, but want to explicitly parse
176 // stuff we do have definitions for.
178 // option 1: auto-parse everything into data structures,
181 // option 2: have a "parse next object" which
182 // doesn't resolve whether it expands its children
183 // yet, and then the user either says "expand" or
184 // "skip" after looking at the name. Anything with
185 // "children" without names can't go through this
188 // Let's try option 2.
193 unsigned char *buffer_start
;
194 unsigned char *buffer_end
;
197 char temp_buffer
[256];
200 enum { TAG_End
=0, TAG_Byte
=1, TAG_Short
=2, TAG_Int
=3, TAG_Long
=4,
201 TAG_Float
=5, TAG_Double
=6, TAG_Byte_Array
=7, TAG_String
=8,
202 TAG_List
=9, TAG_Compound
=10, TAG_Int_Array
=11 };
204 static void nbt_get_string_data(unsigned char *data
, char *buffer
, size_t bufsize
)
206 int len
= data
[0]*256 + data
[1];
208 for (i
=0; i
< len
&& i
+1 < (int) bufsize
; ++i
)
209 buffer
[i
] = (char) data
[i
+2];
213 static char *nbt_peek(nbt
*n
)
215 unsigned char type
= *n
->cur
;
218 nbt_get_string_data(n
->cur
+1, n
->temp_buffer
, sizeof(n
->temp_buffer
));
219 return n
->temp_buffer
;
222 static uint32
nbt_parse_uint32(unsigned char *buffer
)
224 return (buffer
[0] << 24) + (buffer
[1]<<16) + (buffer
[2]<<8) + buffer
[3];
227 static void nbt_skip(nbt
*n
);
229 // skip an item that doesn't have an id or name prefix (usable in lists)
230 static void nbt_skip_raw(nbt
*n
, unsigned char type
)
233 case TAG_Byte
: n
->cur
+= 1; break;
234 case TAG_Short
: n
->cur
+= 2; break;
235 case TAG_Int
: n
->cur
+= 4; break;
236 case TAG_Long
: n
->cur
+= 8; break;
237 case TAG_Float
: n
->cur
+= 4; break;
238 case TAG_Double
: n
->cur
+= 8; break;
239 case TAG_Byte_Array
: n
->cur
+= 4 + 1*nbt_parse_uint32(n
->cur
); break;
240 case TAG_Int_Array
: n
->cur
+= 4 + 4*nbt_parse_uint32(n
->cur
); break;
241 case TAG_String
: n
->cur
+= 2 + (n
->cur
[0]*256 + n
->cur
[1]); break;
243 unsigned char list_type
= *n
->cur
++;
244 unsigned int list_len
= nbt_parse_uint32(n
->cur
);
246 n
->cur
+= 4; // list_len
247 for (i
=0; i
< list_len
; ++i
)
248 nbt_skip_raw(n
, list_type
);
251 case TAG_Compound
: {
252 while (*n
->cur
!= TAG_End
)
254 nbt_skip(n
); // skip the TAG_end
258 assert(n
->cur
<= n
->buffer_end
);
261 static void nbt_skip(nbt
*n
)
263 unsigned char type
= *n
->cur
++;
267 n
->cur
+= (n
->cur
[0]*256 + n
->cur
[1]) + 2;
268 nbt_skip_raw(n
, type
);
272 static void nbt_swap(unsigned char *ptr
, int len
)
275 for (i
=0; i
< (len
>>1); ++i
) {
276 unsigned char t
= ptr
[i
];
277 ptr
[i
] = ptr
[len
-1-i
];
282 // pass in the expected type, fail if doesn't match
283 // returns a pointer to the data, byteswapped if appropriate
284 static void *nbt_get_fromlist(nbt
*n
, unsigned char type
, int *len
)
287 assert(type
!= TAG_Compound
);
288 assert(type
!= TAG_List
); // we could support getting lists of primitives as if they were arrays, but eh
292 case TAG_Byte
: break;
294 case TAG_Short
: nbt_swap(ptr
, 2); break;
295 case TAG_Int
: nbt_swap(ptr
, 4); break;
296 case TAG_Long
: nbt_swap(ptr
, 8); break;
297 case TAG_Float
: nbt_swap(ptr
, 4); break;
298 case TAG_Double
: nbt_swap(ptr
, 8); break;
301 *len
= nbt_parse_uint32(ptr
);
304 case TAG_Int_Array
: {
306 *len
= nbt_parse_uint32(ptr
);
308 for (i
=0; i
< *len
; ++i
)
309 nbt_swap(ptr
+ 4*i
, 4);
313 default: assert(0); // unhandled case
315 nbt_skip_raw(n
, type
);
319 static void *nbt_get(nbt
*n
, unsigned char type
, int *len
)
321 assert(n
->cur
[0] == type
);
322 n
->cur
+= 3 + (n
->cur
[1]*256+n
->cur
[2]);
323 return nbt_get_fromlist(n
, type
, len
);
326 static void nbt_begin_compound(nbt
*n
) // start a compound
328 assert(*n
->cur
== TAG_Compound
);
330 n
->cur
+= 3 + (n
->cur
[1]*256 + n
->cur
[2]);
334 static void nbt_begin_compound_in_list(nbt
*n
) // start a compound
339 static void nbt_end_compound(nbt
*n
) // end a compound
341 assert(*n
->cur
== TAG_End
);
342 assert(n
->nesting
!= 0);
347 // @TODO no interface to get lists from lists
348 static int nbt_begin_list(nbt
*n
, unsigned char type
)
353 ptr
= n
->cur
+ 3 + (n
->cur
[1]*256 + n
->cur
[2]);
357 len
= nbt_parse_uint32(n
->cur
+1);
358 assert(n
->cur
[0] == type
);
359 // @TODO keep a stack with the count to make sure they do it right
365 static void nbt_end_list(nbt
*n
)
370 // raw_block chunk is 16x256x16x4 = 2^(4+8+4+2) = 256KB
372 // if we want to process 64x64x256 at a time, that will be:
373 // 4*4*256KB => 4MB per area in raw_block
375 // (plus we maybe need to decode adjacent regions)
379 typedef fast_chunk parse_chunk
;
381 typedef chunk parse_chunk
;
384 static parse_chunk
*minecraft_chunk_parse(unsigned char *data
, size_t len
)
387 parse_chunk
*c
= NULL
;
389 nbt n_store
, *n
= &n_store
;
390 n
->buffer_start
= data
;
391 n
->buffer_end
= data
+ len
;
392 n
->cur
= n
->buffer_start
;
395 nbt_begin_compound(n
);
396 while ((s
= nbt_peek(n
)) != NULL
) {
397 if (!strcmp(s
, "Level")) {
399 c
= malloc(sizeof(*c
));
401 memset(c
, 0, sizeof(*c
));
402 c
->pointer_to_free
= data
;
404 c
->rb
[15][15][255].block
= 0;
408 nbt_begin_compound(n
);
409 while ((s
= nbt_peek(n
)) != NULL
) {
410 if (!strcmp(s
, "xPos"))
411 c
->xpos
= *(int *) nbt_get(n
, TAG_Int
, 0);
412 else if (!strcmp(s
, "zPos"))
413 c
->zpos
= *(int *) nbt_get(n
, TAG_Int
, 0);
414 else if (!strcmp(s
, "Sections")) {
415 int count
= nbt_begin_list(n
, TAG_Compound
), i
;
417 // this not-a-list case happens in The End and I'm not sure
418 // what it means... possibly one of those silly encodings
419 // where it's not encoded as a list if there's only one?
420 // not worth figuring out
424 for (i
=0; i
< count
; ++i
) {
426 uint8
*light
= NULL
, *blocks
= NULL
, *data
= NULL
, *skylight
= NULL
;
427 nbt_begin_compound_in_list(n
);
428 while ((s
= nbt_peek(n
)) != NULL
) {
430 yi
= * (uint8
*) nbt_get(n
, TAG_Byte
, 0);
431 else if (!strcmp(s
, "BlockLight")) {
432 light
= nbt_get(n
, TAG_Byte_Array
, &len
);
434 } else if (!strcmp(s
, "Blocks")) {
435 blocks
= nbt_get(n
, TAG_Byte_Array
, &len
);
437 } else if (!strcmp(s
, "Data")) {
438 data
= nbt_get(n
, TAG_Byte_Array
, &len
);
440 } else if (!strcmp(s
, "SkyLight")) {
441 skylight
= nbt_get(n
, TAG_Byte_Array
, &len
);
451 // clear data below current max_y
454 while (c
->max_y
< yi
*16) {
455 for (x
=0; x
< 16; ++x
)
456 for (z
=0; z
< 16; ++z
)
457 c
->rb
[z
][x
][c
->max_y
].block
= 0;
462 // now assemble the data
464 int x
,y
,z
, o2
=0,o4
=0;
465 for (y
=0; y
< 16; ++y
) {
466 for (z
=0; z
< 16; ++z
) {
467 for (x
=0; x
< 16; x
+= 2) {
468 raw_block
*rb
= &c
->rb
[15-z
][x
][y
+ yi
*16]; // 15-z because switching to z-up will require flipping an axis
469 rb
[0].block
= blocks
[o4
];
470 rb
[0].light
= light
[o2
] & 15;
471 rb
[0].data
= data
[o2
] & 15;
472 rb
[0].skylight
= skylight
[o2
] & 15;
474 rb
[256].block
= blocks
[o4
+1];
475 rb
[256].light
= light
[o2
] >> 4;
476 rb
[256].data
= data
[o2
] >> 4;
477 rb
[256].skylight
= skylight
[o2
] >> 4;
487 c
->blockdata
[yi
] = blocks
;
489 c
->light
[yi
] = light
;
490 c
->skylight
[yi
] = skylight
;
494 } else if (!strcmp(s
, "HeightMap")) {
495 height
= nbt_get(n
, TAG_Int_Array
, &len
);
506 assert(n
->cur
== n
->buffer_end
);
510 #define MAX_DECODED_CHUNK_X 64
511 #define MAX_DECODED_CHUNK_Z 64
520 static decoded_buffer decoded_buffers
[MAX_DECODED_CHUNK_Z
][MAX_DECODED_CHUNK_X
];
521 void lock_chunk_get_mutex(void);
522 void unlock_chunk_get_mutex(void);
525 fast_chunk
*get_decoded_fastchunk_uncached(int chunk_x
, int chunk_z
)
527 unsigned char *decoded
;
528 compressed_chunk
*cc
;
533 lock_chunk_get_mutex();
534 cc
= get_compressed_chunk(chunk_x
, chunk_z
);
537 unlock_chunk_get_mutex();
544 assert(cc
->data
[4] == 2);
546 inlen
= nbt_parse_uint32(cc
->data
);
547 decoded
= stbi_zlib_decode_malloc_guesssize(cc
->data
+5, inlen
, inlen
*3, &len
);
548 assert(decoded
!= NULL
);
551 lock_chunk_get_mutex();
552 deref_compressed_chunk(cc
);
553 unlock_chunk_get_mutex();
556 fc
= minecraft_chunk_parse(decoded
, len
);
566 decoded_buffer
*get_decoded_buffer(int chunk_x
, int chunk_z
)
568 decoded_buffer
*db
= &decoded_buffers
[chunk_z
&(MAX_DECODED_CHUNK_Z
-1)][chunk_x
&(MAX_DECODED_CHUNK_X
-1)];
570 if (db
->cx
== chunk_x
&& db
->cz
== chunk_z
)
573 free(db
->fc
->pointer_to_free
);
584 db
->fc
= get_decoded_fastchunk_uncached(chunk_x
, chunk_z
);
589 fast_chunk
*get_decoded_fastchunk(int chunk_x
, int chunk_z
)
591 decoded_buffer
*db
= get_decoded_buffer(chunk_x
, chunk_z
);
597 chunk
*get_decoded_chunk_raw(int chunk_x
, int chunk_z
)
599 unsigned char *decoded
;
600 compressed_chunk
*cc
= get_compressed_chunk(chunk_x
, chunk_z
);
606 int inlen
= nbt_parse_uint32(cc
->data
);
608 assert(cc
->data
[4] == 2);
609 decoded
= stbi_zlib_decode_malloc_guesssize(cc
->data
+5, inlen
, inlen
*3, &len
);
610 assert(decoded
!= NULL
);
614 ch
= minecraft_chunk_parse(decoded
, len
);
621 static chunk
*decoded_chunks
[MAX_DECODED_CHUNK_Z
][MAX_DECODED_CHUNK_X
];
622 chunk
*get_decoded_chunk(int chunk_x
, int chunk_z
)
624 chunk
*c
= decoded_chunks
[chunk_z
&(MAX_DECODED_CHUNK_Z
-1)][chunk_x
&(MAX_DECODED_CHUNK_X
-1)];
625 if (c
&& c
->xpos
== chunk_x
&& c
->zpos
== chunk_z
)
628 c
= get_decoded_chunk_raw(chunk_x
, chunk_z
);
629 decoded_chunks
[chunk_z
&(MAX_DECODED_CHUNK_Z
-1)][chunk_x
&(MAX_DECODED_CHUNK_X
-1)] = c
;