diff --git a/src/meson.build b/src/meson.build index 9df8375..d16335a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -5,6 +5,8 @@ feather_src = [ 'logging/Logger.cpp', + 'nbt/NBT.cpp', + 'network/NetworkManager.cpp', 'network/TCPListener.cpp', 'network/TCPClient.cpp', diff --git a/src/nbt/NBT.cpp b/src/nbt/NBT.cpp new file mode 100644 index 0000000..33f2de5 --- /dev/null +++ b/src/nbt/NBT.cpp @@ -0,0 +1,184 @@ +#include "NBT.h" + +#include "cNBT/nbt.h" +#include "cNBT/list.h" + +#include +#include +#include + +namespace NBT +{ + nbt_node* Internal::FindByName(nbt_node* tree, const char* name) + { + return nbt_find_by_name(tree, name); + } + + nbt_node* Internal::ListItem(nbt_node* list, int32_t index) + { + return nbt_list_item(list, index); + } + + Tag Tag::CreateTag(nbt_node *node) + { + switch (node->type) + { + case TAG_BYTE: return DataTag(node); + case TAG_SHORT: return DataTag(node); + case TAG_INT: return DataTag(node); + case TAG_LONG: return DataTag(node); + case TAG_FLOAT: return DataTag(node); + case TAG_DOUBLE: return DataTag(node); + case TAG_BYTE_ARRAY: return ArrayTag(node); + case TAG_STRING: return StringTag(node); + case TAG_LIST: return CreateListTag(node); + case TAG_COMPOUND: return CompoundTag(node); + case TAG_INT_ARRAY: return ArrayTag(node); + case TAG_LONG_ARRAY: return ArrayTag(node); + + case TAG_INVALID: + default: + return NULL; + } + } + + Tag Tag::CreateListTag(nbt_node* node) + { + nbt_type type = node->payload.tag_list->data->type; + switch (type) + { + case TAG_BYTE: return ListTag(node); + case TAG_SHORT: return ListTag(node); + case TAG_INT: return ListTag(node); + case TAG_LONG: return ListTag(node); + case TAG_FLOAT: return ListTag(node); + case TAG_DOUBLE: return ListTag(node); + case TAG_BYTE_ARRAY: return ListTag>(node); + case TAG_STRING: return ListTag(node); + case TAG_LIST: return CreateListTag(node); + case TAG_COMPOUND: return ListTag(node); + case TAG_INT_ARRAY: return ListTag>(node); + case TAG_LONG_ARRAY: return ListTag>(node); + + case TAG_INVALID: + default: + return NULL; + } + } + + const char *Tag::GetName() const + { + return m_node->name ? m_node->name : ""; + } + + size_t Tag::GetLength() const + { + switch (m_node->type) + { + case TAG_BYTE_ARRAY: + return m_node->payload.tag_byte_array.length; + case TAG_INT_ARRAY: + return m_node->payload.tag_int_array.length; + case TAG_LONG_ARRAY: + return m_node->payload.tag_long_array.length; + + case TAG_LIST: + return list_length(&(m_node->payload.tag_list->entry)); + case TAG_COMPOUND: + return list_length(&(m_node->payload.tag_compound->entry)); + + // nbt_size(node) is only used for non-list types because + // it gets the total number of nodes, rather than immediate children + // and it treats arrays as consisting of one node + default: + // will return 1 for most types and 0 for invalid + return nbt_size(m_node); + } + } + + const char *Tag::ToString() const + { + return nbt_dump_ascii(m_node); + } + + std::ostream& operator<<(std::ostream& stream, const Tag& tag) + { + return stream << tag.ToString(); + } + + //================================================== + + + + //================================================== + + template <> + Tag ListTag::Get(int32_t index) const + { + nbt_node* result = nbt_list_item(m_node, index); + return Tag::CreateTag(result); + } + + //================================================== + + CompoundTag::CompoundTag(const char *filename) + : CompoundTag(nbt_parse_path(filename)) + { + } + + CompoundTag::~CompoundTag() + { + nbt_free(m_node); + } + + template + const T CompoundTag::Get(const char *name) const + { + nbt_node *result = nbt_find_by_name(m_node, name); + return T(result); + } + + const Tag CompoundTag::operator[](const char *name) const + { + nbt_node *result = nbt_find_by_name(m_node, name); + + return Tag::CreateTag(result); + } + + //================================================== + + // Byte + template <> int8_t DataTag::GetValue() const { return m_node->payload.tag_byte; } + + // Short + template <> int16_t DataTag::GetValue() const { return m_node->payload.tag_short; } + + // Int + template <> int32_t DataTag::GetValue() const { return m_node->payload.tag_int; } + + // Long + template <> int64_t DataTag::GetValue() const { return m_node->payload.tag_long; } + + // Float + template <> float DataTag::GetValue() const { return m_node->payload.tag_float; } + + // Double + template <> double DataTag::GetValue() const { return m_node->payload.tag_double; } + + // String + template <> const char* DataTag::GetValue() const { return m_node->payload.tag_string; } + + //================================================== + + // Byte Array + template <> const int8_t* ArrayTag::GetValue() const { return (const int8_t*)(m_node->payload.tag_byte_array.data); } + + // Int Array + template <> const int32_t* ArrayTag::GetValue() const { return m_node->payload.tag_int_array.data; } + + // Long Array + template <> const int64_t* ArrayTag::GetValue() const { return m_node->payload.tag_long_array.data; } + + // String + template <> const char* StringTag::GetValue() const { return m_node->payload.tag_string; } +} \ No newline at end of file diff --git a/src/nbt/NBT.h b/src/nbt/NBT.h new file mode 100644 index 0000000..a8b9352 --- /dev/null +++ b/src/nbt/NBT.h @@ -0,0 +1,119 @@ +#pragma once + +#include + +#include +#include +#include + +struct nbt_node; +struct list_head; + +namespace NBT +{ + class Tag + { + protected: + nbt_node* m_node; + Tag(nbt_node *node) : m_node(node) {} + + static Tag CreateTag(nbt_node* node); + static Tag CreateListTag(nbt_node* node); + public: + + const char* GetName() const; + + // Get the number of iterable immediate children + size_t GetLength() const; + const char* ToString() const; + }; + + // Operator overload for ostream + std::ostream& operator<<(std::ostream& stream, const Tag& tag); + + template + class DataTag : public Tag + { + public: + DataTag(nbt_node* node) : Tag(node) {} + + T GetValue() const; + + inline operator T() const { return GetValue(); } + }; + + template + class ArrayTag : public DataTag + { + public: + ArrayTag(nbt_node* node) : DataTag(node) {} + + const T* GetValue() const; + + const T* begin() { return GetValue(); } + const T* end() { return &(GetValue()[this->GetLength()]); } + }; + + using StringTag = ArrayTag; + + template + class ListTag : public Tag + { + public: + ListTag(nbt_node *node) : Tag(node) {} + + T Get(int32_t index) const; + + inline const T operator[](int32_t index) const { return Get(index); } + }; + + // A Compound Tag is an unordered list of named tags + class CompoundTag : public Tag + { + public: + CompoundTag(nbt_node* node) : Tag(node) {} + + CompoundTag(const char *filename); + ~CompoundTag(); + + template + const ListTag GetList(const char* name) const; + + template + const T Get(const char* name) const; + + const Tag operator[](const char* name) const; + }; + + //================================================== + + namespace Internal + { + nbt_node* FindByName(nbt_node* tree, const char* name); + nbt_node* ListItem(nbt_node* list, int32_t index); + } + + //================================================== + + template + T ListTag::Get(int32_t index) const + { + nbt_node* result = Internal::ListItem(m_node, index); + return DataTag(result); + } + + //================================================== + + template + const ListTag CompoundTag::GetList(const char *name) const + { + nbt_node *result = Internal::FindByName(m_node, name); + + if (result == NULL) + return NULL; + //if (result->type != TAG_LIST) + // return NULL; + + return ListTag(result); + } +} \ No newline at end of file