1 /* 2 * Copyright (c) 2017 Juliette Foucaut & Doug Binks 3 * 4 * This software is provided 'as-is', without any express or implied 5 * warranty. In no event will the authors be held liable for any damages 6 * arising from the use of this software. 7 * 8 * Permission is granted to anyone to use this software for any purpose, 9 * including commercial applications, and to alter it and redistribute it 10 * freely, subject to the following restrictions: 11 * 12 * 1. The origin of this software must not be misrepresented; you must not 13 * claim that you wrote the original software. If you use this software 14 * in a product, an acknowledgement in the product documentation would be 15 * appreciated but is not required. 16 * 2. Altered source versions must be plainly marked as such, and must not be 17 * misrepresented as being the original software. 18 * 3. This notice may not be removed or altered from any source distribution. 19 */ 20 #pragma once 21 22 #include <stdint.h> 23 #include "miniz.h" 24 25 #ifdef __cplusplus 26 extern "C" { 27 #endif 28 29 #define ENKI_MI_REGION_CHUNKS_NUMBER 1024 30 31 // http://web.archive.org/web/20110723210920/http://www.minecraft.net/docs/NBT.txt 32 typedef enum 33 { 34 enkiNBTTAG_End = 0, 35 enkiNBTTAG_Byte = 1, 36 enkiNBTTAG_Short = 2, 37 enkiNBTTAG_Int = 3, 38 enkiNBTTAG_Long = 4, 39 enkiNBTTAG_Float = 5, 40 enkiNBTTAG_Double = 6, 41 enkiNBTTAG_Byte_Array = 7, 42 enkiNBTTAG_String = 8, 43 enkiNBTTAG_List = 9, 44 enkiNBTTAG_Compound = 10, 45 enkiNBTTAG_Int_Array = 11, 46 } enkiNBTTAG_ID; 47 48 49 typedef struct enkiNBTTagHeader_s 50 { 51 char* pName; 52 53 // if the tag is a list, we need the following variables 54 int32_t listNumItems; 55 int32_t listCurrItem; 56 uint8_t listItemTagId; 57 58 // the tagId of type enkiNBTTAG_ID 59 uint8_t tagId; 60 } enkiNBTTagHeader; 61 62 63 const char* enkiGetNBTTagIDAsString( uint8_t tagID_ ); 64 const char* enkiGetNBTTagHeaderIDAsString( enkiNBTTagHeader tagID_ ); 65 66 typedef struct enkiNBTDataStream_s 67 { 68 enkiNBTTagHeader parentTags[ 512 ]; 69 enkiNBTTagHeader currentTag; 70 uint8_t* pCurrPos; 71 uint8_t* pDataEnd; 72 uint8_t* pData; 73 uint8_t* pNextTag; 74 uint8_t* pAllocation; 75 uint32_t dataLength; 76 int32_t level; 77 } enkiNBTDataStream; 78 79 80 // Initialize stream from memory pointer. 81 // pData_ and it's contents should remain valid until 82 // after enkiNBTDataStream no longer needed. 83 // Contents of buffer will be modified for easier reading, 84 // namely tag name strings will moved down a byte, null terminated, 85 // and prefixed with 0xFF instead of int16_t string length. 86 // Make a copy if you need to use the buffer in another lib. 87 // Other strings in file will not be altered. 88 // pUnCompressedData_ should be freed by caller. 89 // FreeMemoryAllocated() should still be called to free any internal allocations. 90 void enkiNBTInitFromMemoryUncompressed( enkiNBTDataStream* pStream_, uint8_t* pUnCompressedData_, uint32_t dataSize_ ); 91 92 // Initialize stream from memory pointer to compressed content. 93 // This function will allocate space for uncompressed stream and decompress it with zlib. 94 // If uncompressedSizeHint_ > compressedDataSize_ it will be used as the starting hint size for allocating 95 // the uncompressed size. 96 // returns 1 if successfull, 0 if not. 97 int enkiNBTInitFromMemoryCompressed( enkiNBTDataStream* pStream_, uint8_t* pCompressedData_, 98 uint32_t compressedDataSize_, uint32_t uncompressedSizeHint_ ); 99 100 101 // returns 0 if no next tag, 1 if there was 102 int enkiNBTReadNextTag( enkiNBTDataStream* pStream_ ); 103 104 105 // Rewind stream so it can be read again from beginning 106 void enkiNBTRewind( enkiNBTDataStream* pStream_ ); 107 108 // Frees any internally allocated memory. 109 void enkiNBTFreeAllocations( enkiNBTDataStream* pStream_ ); 110 111 int8_t enkiNBTReadInt8( enkiNBTDataStream* pStream_ ); 112 int8_t enkiNBTReadByte( enkiNBTDataStream* pStream_ ); 113 int16_t enkiNBTReadInt16( enkiNBTDataStream* pStream_ ); 114 int16_t enkiNBTReadShort( enkiNBTDataStream* pStream_ ); 115 int32_t enkiNBTReadInt32( enkiNBTDataStream* pStream_ ); 116 int32_t enkiNBTReadInt( enkiNBTDataStream* pStream_ ); 117 float enkiNBTReadFloat( enkiNBTDataStream* pStream_ ); 118 int64_t enkiNBTReadInt64( enkiNBTDataStream* pStream_ ); 119 int64_t enkiNBTReadlong( enkiNBTDataStream* pStream_ ); 120 double enkiNBTReadDouble( enkiNBTDataStream* pStream_ ); 121 122 typedef struct enkiNBTString_s 123 { 124 int16_t size; 125 const char* pStrNotNullTerminated; 126 } enkiNBTString; 127 128 enkiNBTString enkiNBTReadString( enkiNBTDataStream* pStream_ ); 129 130 typedef struct enkiRegionFile_s 131 { 132 uint8_t* pRegionData; 133 uint32_t regionDataSize; 134 } enkiRegionFile; 135 136 // enkiRegionFileInit simply zeros data 137 void enkiRegionFileInit( enkiRegionFile* pRegionFile_ ); 138 139 enkiRegionFile enkiRegionFileLoad( FILE* fp_ ); 140 141 void enkiInitNBTDataStreamForChunk( enkiRegionFile regionFile_, int32_t chunkNr_, enkiNBTDataStream* pStream_ ); 142 143 int32_t enkiGetTimestampForChunk( enkiRegionFile regionFile_, int32_t chunkNr_ ); 144 145 // enkiFreeRegionFileData frees data allocated in enkiRegionFile 146 void enkiRegionFileFreeAllocations( enkiRegionFile* pRegionFile_ ); 147 148 // Check if lhs_ and rhs_ are equal, return 1 if so, 0 if not. 149 // Safe to pass in NULL for either 150 // Note that both NULL gives 0. 151 int enkiAreStringsEqual( const char* lhs_, const char* rhs_ ); 152 153 #define ENKI_MI_NUM_SECTIONS_PER_CHUNK 16 154 #define ENKI_MI_SIZE_SECTIONS 16 155 156 typedef struct enkiMICoordinate_s 157 { 158 int32_t x; 159 int32_t y; // height 160 int32_t z; 161 } enkiMICoordinate; 162 163 typedef struct enkiChunkBlockData_s 164 { 165 uint8_t* sections[ ENKI_MI_NUM_SECTIONS_PER_CHUNK ]; 166 int32_t xPos; // section coordinates 167 int32_t zPos; // section coordinates 168 int32_t countOfSections; 169 } enkiChunkBlockData; 170 171 // enkiChunkInit simply zeros data 172 void enkiChunkInit( enkiChunkBlockData* pChunk_ ); 173 174 // enkiNBTReadChunk gets a chunk from an enkiNBTDataStream 175 // No allocation occurs - section data points to enkiNBTDataStream. 176 // pStream_ mush be kept valid whilst chunk is in use. 177 enkiChunkBlockData enkiNBTReadChunk( enkiNBTDataStream* pStream_ ); 178 179 180 enkiMICoordinate enkiGetChunkOrigin( enkiChunkBlockData* pChunk_ ); 181 182 // get the origin of a section (0 <-> ENKI_MI_NUM_SECTIONS_PER_CHUNK). 183 enkiMICoordinate enkiGetChunkSectionOrigin( enkiChunkBlockData* pChunk_, int32_t section_ ); 184 185 // sectionOffset_ is the position from enkiGetChunkSectionOrigin 186 // Performs no safety checks. 187 // check pChunk_->sections[ section_ ] for NULL first in your code. 188 // and ensure sectionOffset_ coords with 0 to ENKI_MI_NUM_SECTIONS_PER_CHUNK 189 uint8_t enkiGetChunkSectionVoxel( enkiChunkBlockData* pChunk_, int32_t section_, enkiMICoordinate sectionOffset_ ); 190 191 uint32_t* enkiGetMineCraftPalette(); //returns a 256 array of uint32_t's in uint8_t rgba order. 192 193 #ifdef __cplusplus 194 }; 195 #endif 196