From b58ab3d00c700291cf7c69eaf3eb9ae019539a4c Mon Sep 17 00:00:00 2001 From: TCA Date: Sat, 20 Apr 2024 14:31:21 +0200 Subject: [PATCH] Added blockPrint --- .gitignore | 3 +- Makefile | 11 +++-- doc/Doxyfile.conf | 2 +- doc/{src => pages}/userManual.md | 0 doc/{src => pages}/utilities.md | 0 src/blockPrint.c | 82 ++++++++++++++++++++++++++++++++ src/chunkExtractor.c | 3 +- src/dir.dox | 5 -- src/lib/chunkParser.c | 1 + src/lib/chunkParser.h | 9 +++- src/lib/errorDefs.h | 9 +++- src/lib/generator.c | 5 +- src/lib/generator.h | 7 ++- src/lib/hTable.c | 18 ++++--- src/lib/hTable.h | 19 +++++++- src/lib/model.c | 5 ++ src/lib/model.h | 11 +++++ src/lib/regionParser.c | 7 +-- src/lib/regionParser.h | 4 ++ src/modelGenerator.c | 3 +- src/radiusGenerator.c | 9 +--- src/regionFileReader.c | 5 +- 22 files changed, 174 insertions(+), 44 deletions(-) rename doc/{src => pages}/userManual.md (100%) rename doc/{src => pages}/utilities.md (100%) create mode 100644 src/blockPrint.c diff --git a/.gitignore b/.gitignore index 2927482..37230e6 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,5 @@ mtlGen *Check* tests/benchmark mtlFiles -doc/build/* \ No newline at end of file +doc/build/* +blockPrint \ No newline at end of file diff --git a/Makefile b/Makefile index 69b154b..ea0bdf6 100644 --- a/Makefile +++ b/Makefile @@ -14,10 +14,10 @@ ifneq (,$(findstring MSYS,$(UNAME))) endif all: CFLAGS := -O3 -all: radiusGenerator modelGenerator chunkExtractor regionFileReader +all: radiusGenerator modelGenerator chunkExtractor regionFileReader blockPrint debug: CFLAGS := -Wall -Werror -Wpedantic -g -debug: radiusGenerator modelGenerator chunkExtractor regionFileReader +debug: radiusGenerator modelGenerator chunkExtractor regionFileReader blockPrint cNBT.o: gcc cNBT/buffer.c -o cNBT/buffer.o -c $(CFLAGS) @@ -53,6 +53,9 @@ modelGenerator: model.o generator.o hTable.o chunkParser.o cNBT.o src/modelGener radiusGenerator: model.o generator.o hTable.o chunkParser.o regionParser.o cNBT.o src/radiusGenerator.c gcc src/radiusGenerator.c generator.o model.o regionParser.o hTable.o chunkParser.o cNBT.o $(ZLIB) -lm -o radiusGenerator $(CFLAGS) +blockPrint: src/blockPrint.c chunkParser.o cNBT.o hTable.o + gcc src/blockPrint.c chunkParser.o cNBT.o hTable.o -o blockPrint -lm $(CFLAGS) + cNBT.ow: x86_64-w64-mingw32-gcc-win32 cNBT/buffer.c -o cNBT/buffer.ow -c $(CFLAGS) x86_64-w64-mingw32-gcc-win32 cNBT/nbt_parsing.c -o cNBT/nbt_parsing.ow -c $(CFLAGS) @@ -103,6 +106,8 @@ clean: rm -f regionFileReader rm -f regionFileReader.exe rm -rf doc/build + rm -f blockPrint + rm -f blockPrint.exe check: hTable.o regionParser.o chunkParser.o cNBT.o model.o #hTable tests @@ -128,5 +133,5 @@ check: hTable.o regionParser.o chunkParser.o cNBT.o model.o doc: doc/build/html -doc/build/html: src/lib/*.h src/*.c src/lib/*.c doc/Doxyfile.conf src/dir.dox doc/src/* +doc/build/html: src/lib/*.h src/*.c src/lib/*.c doc/Doxyfile.conf src/dir.dox doc/pages/* doxygen ./doc/Doxyfile.conf diff --git a/doc/Doxyfile.conf b/doc/Doxyfile.conf index f3a41fc..12632d0 100644 --- a/doc/Doxyfile.conf +++ b/doc/Doxyfile.conf @@ -864,7 +864,7 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = ./src ./doc/index.md ./doc/src +INPUT = ./src ./doc/index.md ./doc/pages # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/doc/src/userManual.md b/doc/pages/userManual.md similarity index 100% rename from doc/src/userManual.md rename to doc/pages/userManual.md diff --git a/doc/src/utilities.md b/doc/pages/utilities.md similarity index 100% rename from doc/src/utilities.md rename to doc/pages/utilities.md diff --git a/src/blockPrint.c b/src/blockPrint.c new file mode 100644 index 0000000..3629c0d --- /dev/null +++ b/src/blockPrint.c @@ -0,0 +1,82 @@ +/*! + @file blockPrint.c + @brief Prints the number of each block in a chunk + @details This program prints the number of each block in a chunk +*/ + +#include +#include +#include "./lib/errorDefs.h" +#include "./lib/chunkParser.h" +#include "./lib/hTable.h" + +/*! + @brief Loads an nbt file and prints the number of each block in a chunk + @details the association of block type to block count is stored in a hash table + @see chunkParser.h + @see hTable.h +*/ +int main(int argc, char** argv){ + if(argc < 2){ + argCountError("blockPrint "); + } + unsigned char* data; + long sz; + { + FILE* file = fopen(argv[1], "rb"); + if(file == NULL){ + fileError(argv[1], "opened"); + } + if(fseek(file, 0, SEEK_END) != 0){ + fileError(argv[1], "seeked"); + } + sz = ftell(file); + if(fseek(file, 0, SEEK_SET) != 0){ + fileError(argv[1], "seeked"); + } + data = malloc(sz); + if(fread(data, sz, 1, file) != 1){ + fileError(argv[1], "read"); + } + fclose(file); + } + section sections[maxSections]; + int sectionN = getSections(data, sz, sections); + free(data); + hashTable* blockCount = initHashTable(49152); //max blocks in chunk divided by 2 + for(int i = 0; i < sectionN; i++){ + int outLen; + unsigned int* blockStates = getBlockStates(sections[i], &outLen); + if(blockStates == NULL){ + char* key = sections[i].blockPalette[0]; + if(getVal(blockCount, key) == NULL){ + int* val = malloc(sizeof(int)); + insertHashItem(blockCount, key, val); + } + else{ + int* val = getVal(blockCount, key); + *val += 1; + } + } + else{ + for(int j = 0; j < outLen; j++){ + char* key = sections[i].blockPalette[blockStates[j]]; + if(getVal(blockCount, key) == NULL){ + int* val = malloc(sizeof(int)); + insertHashItem(blockCount, key, val); + } + else{ + int* val = getVal(blockCount, key); + *val += 1; + } + } + } + free(blockStates); + } + freeSections(sections, sectionN); + forHashTableItem(blockCount){ + printf("%s: %d\n", item->key, *(int*)item->value); + } + freeHashTable(blockCount, free); + return EXIT_SUCCESS; +} diff --git a/src/chunkExtractor.c b/src/chunkExtractor.c index 391f99c..0e04b0f 100644 --- a/src/chunkExtractor.c +++ b/src/chunkExtractor.c @@ -19,11 +19,10 @@ @details Loads a chunk from a region file using the regionParser library, then writes it to a file using extractChunk. @see regionParser.h @see @ref extractChunk - @return The chunk object */ int main(int argc, char** argv){ if(argc < 3){ - argCountError(); + argCountError("chunkExtractor "); } for(int i = 3; i < argc; i+=3){ int x = atoi(argv[i - 1]); diff --git a/src/dir.dox b/src/dir.dox index 245cae5..f871957 100644 --- a/src/dir.dox +++ b/src/dir.dox @@ -10,8 +10,3 @@ @brief Directory for library sourcecode @details contains all of the C libraries */ - -/*! -@dir /src/scripts -@brief Directory for Python utility scripts -*/ diff --git a/src/lib/chunkParser.c b/src/lib/chunkParser.c index a74141a..d51fdf9 100644 --- a/src/lib/chunkParser.c +++ b/src/lib/chunkParser.c @@ -314,5 +314,6 @@ void freeSections(section* sections, int sectionLen){ free(sections[i].blockPalette[n]); } free(sections[i].blockPalette); + free(sections[i].blockData); } } diff --git a/src/lib/chunkParser.h b/src/lib/chunkParser.h index dcc08e0..9483f27 100644 --- a/src/lib/chunkParser.h +++ b/src/lib/chunkParser.h @@ -4,6 +4,9 @@ @details This file contains functions for parsing chunk data */ +#ifndef CHUNKPARSER_H +#define CHUNKPARSER_H + /*! @defgroup chunkParser Chunk Parser @brief Chunk data parsing functions @@ -120,7 +123,7 @@ unsigned int getSections(unsigned char* nbtFileData, long sz, section* sections) @details Returns NULL if it cannot be created. Be sure to free the result once you are done with it. @param s The section to create the block states from @param outLen The length of the block states array - @return The block states array + @return The block states array, or NULL if it cannot be created @ingroup chunkParser */ unsigned int* getBlockStates(section s, int* outLen); @@ -155,4 +158,6 @@ char** createGlobalPalette(section* sections, int len, int* outLen, bool freeSec @param sectionLen The length of the sections array @ingroup chunkParser */ -void freeSections(section* sections, int sectionLen); \ No newline at end of file +void freeSections(section* sections, int sectionLen); + +#endif diff --git a/src/lib/errorDefs.h b/src/lib/errorDefs.h index 514bdbf..f7e5fd8 100644 --- a/src/lib/errorDefs.h +++ b/src/lib/errorDefs.h @@ -7,6 +7,10 @@ //Since the ERRNO macros are very unspecific and as far as I can see usually associated with errors a kernel may encounter, I have only loosely associated them with my own error convention +#include +#include +#include + /*! @defgroup errorDefs Error Definitions @brief Contains error definitions for the project @@ -106,10 +110,11 @@ /*! * @def argCountError * @brief Reports an error when an invalid amount of arguments is provided + * @param usage The usage of the program * @ingroup errorDefs */ -#define argCountError() \ - fprintf(stderr, "Invalid number of arguments was provided\n."); \ +#define argCountError(usage) \ + fprintf(stderr, "Invalid number of arguments was provided\n" usage "\n"); \ errno = EINVAL; \ perror("Arg count error."); \ exit(EXIT_FAILURE); diff --git a/src/lib/generator.c b/src/lib/generator.c index 15f65aa..1328955 100644 --- a/src/lib/generator.c +++ b/src/lib/generator.c @@ -39,8 +39,8 @@ model generateFromNbt(unsigned char* data, int dataSize, hashTable* materials, h freeHashTable(materials); } if(!f){ - long count = cullFaces(&cubeModel, !b, objects); - printf("%ld model faces culled\n", count); + cullFaces(&cubeModel, !b, objects); + //printf("%ld model faces culled\n", count); } model newModel = cubeModelToModel(&cubeModel, objects); newModel.materialArr = materialsArr; @@ -59,7 +59,6 @@ cubeModel createCubeModel(section* sections, int sectionLen, hashTable* material for(int i = 0; i < sectionLen; i++){ //create the block state array unsigned int* states = getBlockStates(sections[i], NULL); - free(sections[i].blockData); //if we want to do face culling we first need to actually have all the blocks in one place for(int x = 0; x < 16; x++){ for(int y = 0; y < 16; y++){ diff --git a/src/lib/generator.h b/src/lib/generator.h index 8a02924..d1adeed 100644 --- a/src/lib/generator.h +++ b/src/lib/generator.h @@ -4,6 +4,9 @@ @details This file contains functions for generating 3d models from nbt data */ +#ifndef GENERATOR_H +#define GENERATOR_H + #include #include "model.h" #include "chunkParser.h" @@ -69,4 +72,6 @@ model generateFromNbt(unsigned char* data, int dataSize, hashTable* materials, h @param objects The hashTable to free @ingroup generator */ -void freeObjectsHashTable(hashTable* objects); \ No newline at end of file +void freeObjectsHashTable(hashTable* objects); + +#endif diff --git a/src/lib/hTable.c b/src/lib/hTable.c index 7ed591e..cd9e61a 100644 --- a/src/lib/hTable.c +++ b/src/lib/hTable.c @@ -52,20 +52,24 @@ hashTable* initHashTable(size_t size){ /*! @brief Frees a given hash item @param item the item to free + @param freeValue the function to free the value of the item */ -static void freeHashItem(struct hTableItem* item){ +static void freeHashItem(struct hTableItem* item, freeFunction freeValue){ if(item->next != NULL){ - freeHashItem(item->next); + freeHashItem(item->next, freeValue); + } + if(freeValue != NULL){ + freeValue(item->value); } free(item->key); free(item); } -void freeHashTable(hashTable* table){ +void freeHashTable(hashTable* table, freeFunction freeValue){ for(int i = 0; i < table->size; i++){ struct hTableItem* item = table->items[i]; if(item != NULL){ - freeHashItem(item); + freeHashItem(item, freeValue); table->items[i] = NULL; } } @@ -83,14 +87,14 @@ int insertHashItem(hashTable* table, const char* key, const void* value){ } else if(strcmp(key, currentItem->key) == 0){ //if it isn't we try updating it currentItem->value = (void*)value; - freeHashItem(newItem); + freeHashItem(newItem, NULL); } else{ //else we navigate the linked list struct hTableItem* nextItem = currentItem->next; while(nextItem != NULL){ //as long as the next item isn't NULL if(strcmp(key, currentItem->key) == 0){ //we try updating currentItem->value = (void*)value; - freeHashItem(newItem); + freeHashItem(newItem, NULL); return table->count; } else{ //or move forward @@ -100,7 +104,7 @@ int insertHashItem(hashTable* table, const char* key, const void* value){ } if(strcmp(key, currentItem->key) == 0){ //one last try at updating currentItem->value = (void*)value; - freeHashItem(newItem); + freeHashItem(newItem, NULL); return table->count; } currentItem->next = newItem; diff --git a/src/lib/hTable.h b/src/lib/hTable.h index 3655a81..849e452 100644 --- a/src/lib/hTable.h +++ b/src/lib/hTable.h @@ -3,6 +3,9 @@ @brief A hash table implementation */ +#ifndef HTABLE_H +#define HTABLE_H + /*! @defgroup hTable Hash Table @brief A hash table implementation @@ -56,10 +59,19 @@ typedef struct{ int count; } hashTable; +/*! + @typedef freeFunction + @brief A function pointer type for freeing memory + @param ptr The pointer to free + @ingroup hTable +*/ +typedef void (*freeFunction)(void* ptr); + /*! @def forHashTableItem(key, table) @brief Macro wrapper for two for loops that provides a struct hTableItem* item variable for your use @param table The hash table to get the index for + @details Provides a struct hTableItem* item variable for your use @ingroup hTable */ #define forHashTableItem(table) \ @@ -77,9 +89,10 @@ hashTable* initHashTable(size_t size); /*! @brief Frees all the allocated memory in the hash table including the items, but not the values of the items. @param table The hash table to free + @param freeValue The function to free the values of the items, can be NULL @ingroup hTable */ -void freeHashTable(hashTable* table); +void freeHashTable(hashTable* table, freeFunction freeValue); /*! @brief Inserts the given void* as the value of the given key in the given hashTable. @@ -107,4 +120,6 @@ void* getVal(hashTable* table, const char* key); @return The array of value pointers @ingroup hTable */ -void** hashTableToArray(hashTable* table); \ No newline at end of file +void** hashTableToArray(hashTable* table); + +#endif diff --git a/src/lib/model.c b/src/lib/model.c index fc263db..fd07154 100644 --- a/src/lib/model.c +++ b/src/lib/model.c @@ -597,6 +597,11 @@ hashTable* getMaterials(char* filename){ return result; } +void freeMaterial(material* m){ + free(m->name); + free(m); +} + hashTable* readWavefront(char* filename, hashTable* materials, unsigned int side){ FILE* fp = fopen(filename, "r"); if(fp == NULL){ diff --git a/src/lib/model.h b/src/lib/model.h index e960267..9d11cca 100644 --- a/src/lib/model.h +++ b/src/lib/model.h @@ -3,6 +3,9 @@ @brief Definitions for 3D model structs and functions */ +#ifndef MODEL_H +#define MODEL_H + /*! @defgroup model 3D Model @brief Definitions for 3D model structs and functions @@ -510,3 +513,11 @@ cube createGenericCube(unsigned int side); @ingroup model */ object modelToObject(const model* m, const char* type); + +/*! + @brief Frees a material struct + @param m The material to free +*/ +void freeMaterial(material* m); + +#endif diff --git a/src/lib/regionParser.c b/src/lib/regionParser.c index 9a4f846..8e02b41 100644 --- a/src/lib/regionParser.c +++ b/src/lib/regionParser.c @@ -120,12 +120,13 @@ static int getChunkData(chunk* thisChunk, FILE* regionFile, char* regionFileName } while(res == -5); } - - thisChunk->byteLength = buffSize; - buff = realloc(buff, buffSize); if(res < 0){ + free(data); + free(buff); return res; } + thisChunk->byteLength = buffSize; + buff = realloc(buff, buffSize); thisChunk->data = buff; free(data); } diff --git a/src/lib/regionParser.h b/src/lib/regionParser.h index b6845d5..b0d4f2c 100644 --- a/src/lib/regionParser.h +++ b/src/lib/regionParser.h @@ -3,6 +3,8 @@ @brief A parser for region files */ +#ifndef REGIONPARSER_H + /*! @defgroup regionParser Region Parser @brief A parser for region files @@ -146,3 +148,5 @@ chunk* getChunks(FILE* regionFile); @ingroup regionParser */ chunk extractChunk(char* regionDirPath, int x, int z); + +#endif diff --git a/src/modelGenerator.c b/src/modelGenerator.c index 9bf65a0..11af7d5 100644 --- a/src/modelGenerator.c +++ b/src/modelGenerator.c @@ -23,11 +23,10 @@ @see readWavefront @see generateFromNbt @see generateModel - @return The exit status */ int main(int argc, char** argv){ if(argc < 2){ - argCountError(); + argCountError("modelGenerator ..."); } bool yLim = false; //if we wan't to remove some verticality int upLim = 0; //y+ cutoff diff --git a/src/radiusGenerator.c b/src/radiusGenerator.c index 318fb04..066d9d9 100644 --- a/src/radiusGenerator.c +++ b/src/radiusGenerator.c @@ -122,7 +122,7 @@ int main(int argc, char** argv){ //very similar to modelGenerator if(argc < 5){ - argCountError(); + argCountError("radiusGenerator "); } bool yLim = false; //if we want to int upLim = 0; @@ -295,12 +295,7 @@ int main(int argc, char** argv){ sem_destroy(sem); sharedFree(sem, sizeof(sem_t)); if(materials != NULL){ - forHashTableItem(materials){ - material* mat = (material*)item->value; - free(mat->name); - free(mat); - } - freeHashTable(materials); + freeHashTable(materials, (freeFunction)freeMaterial); } if(objects != NULL){ freeObjectsHashTable(objects); diff --git a/src/regionFileReader.c b/src/regionFileReader.c index a0f7757..ebcc7d9 100644 --- a/src/regionFileReader.c +++ b/src/regionFileReader.c @@ -18,12 +18,11 @@ @brief Extracts all chunks from all region files @details Loads all chunks from all region files using the regionParser library, then writes them to files in the given directories. @see regionParser.h - @see @ref extractChunk - @return The exit status + @see extractChunk */ int main(int argc, char** argv){ if(argc < 2){ - argCountError(); + argCountError("regionFileReader "); } //foreach argument for(int i = 2; i < argc; i+=2){