From f1f783877f0f8338a225244faff4e40efe10a4ce Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 21 Jul 2018 18:07:45 +0200 Subject: NBT: rework type system --- src/NBT/ByteArrayTag.hpp | 8 +- src/NBT/ByteTag.hpp | 7 +- src/NBT/CompoundTag.hpp | 10 ++- src/NBT/DoubleTag.hpp | 7 +- src/NBT/EndTag.hpp | 9 ++- src/NBT/FloatTag.hpp | 7 +- src/NBT/IntArrayTag.hpp | 7 +- src/NBT/IntTag.hpp | 7 +- src/NBT/ListTag.hpp | 31 ++++---- src/NBT/LongArrayTag.hpp | 7 +- src/NBT/LongTag.hpp | 7 +- src/NBT/ShortTag.hpp | 7 +- src/NBT/StringTag.hpp | 7 +- src/NBT/Tag.cpp | 194 +++++++++-------------------------------------- src/NBT/Tag.hpp | 63 ++++++++++----- src/World/Chunk.cpp | 8 +- src/World/Chunk.hpp | 4 +- 17 files changed, 162 insertions(+), 228 deletions(-) diff --git a/src/NBT/ByteArrayTag.hpp b/src/NBT/ByteArrayTag.hpp index 1e4f2f9..0d58dc8 100644 --- a/src/NBT/ByteArrayTag.hpp +++ b/src/NBT/ByteArrayTag.hpp @@ -40,12 +40,16 @@ private: const uint8_t *value; public: + static const MakeType Type; + + ByteArrayTag(Buffer *buffer) { len = buffer->get32(); value = buffer->get(len); } - virtual Type getType() const { - return Type::ByteArray; + + virtual const TagType & getType() const { + return Type; } virtual void print(std::ostream& os, const std::string &indent) const { diff --git a/src/NBT/ByteTag.hpp b/src/NBT/ByteTag.hpp index 28b8b1a..c578b9c 100644 --- a/src/NBT/ByteTag.hpp +++ b/src/NBT/ByteTag.hpp @@ -37,12 +37,15 @@ private: uint8_t value; public: + static const MakeType Type; + + ByteTag(Buffer *buffer) { value = buffer->get8(); } - virtual Type getType() const { - return Type::Byte; + virtual const TagType & getType() const { + return Type; } virtual void print(std::ostream& os, const std::string &) const { diff --git a/src/NBT/CompoundTag.hpp b/src/NBT/CompoundTag.hpp index 310b995..68e2390 100644 --- a/src/NBT/CompoundTag.hpp +++ b/src/NBT/CompoundTag.hpp @@ -26,6 +26,7 @@ #pragma once +#include "EndTag.hpp" #include "Tag.hpp" #include @@ -37,18 +38,21 @@ namespace NBT { class CompoundTag : public Tag, public std::unordered_map> { public: + static const MakeType Type; + + CompoundTag(Buffer *buffer) { while (true) { std::pair> v = Tag::readNamedTag(buffer); - if (v.second->getType() == Type::End) + if (v.second->getType() == EndTag::Type) break; insert(std::move(v)); } } - virtual Type getType() const { - return Type::Compound; + virtual const TagType & getType() const { + return Type; } virtual void print(std::ostream& os, const std::string &indent) const { diff --git a/src/NBT/DoubleTag.hpp b/src/NBT/DoubleTag.hpp index 3dfdb74..b83efe2 100644 --- a/src/NBT/DoubleTag.hpp +++ b/src/NBT/DoubleTag.hpp @@ -37,12 +37,15 @@ private: const uint8_t *ptr; public: + static const MakeType Type; + + DoubleTag(Buffer *buffer) { ptr = buffer->get(8); } - virtual Type getType() const { - return Type::Double; + virtual const TagType & getType() const { + return Type; } virtual void print(std::ostream& os, const std::string &) const { diff --git a/src/NBT/EndTag.hpp b/src/NBT/EndTag.hpp index 5f771fd..167412a 100644 --- a/src/NBT/EndTag.hpp +++ b/src/NBT/EndTag.hpp @@ -34,10 +34,13 @@ namespace NBT { class EndTag : public Tag { public: - EndTag() {} + static const MakeType Type; - virtual Type getType() const { - return Type::End; + + EndTag(Buffer *) {} + + virtual const TagType & getType() const { + return Type; } virtual void print(std::ostream&, const std::string &) const { diff --git a/src/NBT/FloatTag.hpp b/src/NBT/FloatTag.hpp index 4442f1a..8748bc6 100644 --- a/src/NBT/FloatTag.hpp +++ b/src/NBT/FloatTag.hpp @@ -36,12 +36,15 @@ class FloatTag : public Tag { const uint8_t *ptr; public: + static const MakeType Type; + + FloatTag(Buffer *buffer) { ptr = buffer->get(4); } - virtual Type getType() const { - return Type::Float; + virtual const TagType & getType() const { + return Type; } virtual void print(std::ostream& os, const std::string &) const { diff --git a/src/NBT/IntArrayTag.hpp b/src/NBT/IntArrayTag.hpp index b7a27b4..67c25b1 100644 --- a/src/NBT/IntArrayTag.hpp +++ b/src/NBT/IntArrayTag.hpp @@ -40,13 +40,16 @@ private: const uint8_t *ptr; public: + static const MakeType Type; + + IntArrayTag(Buffer *buffer) { len = buffer->get32(); ptr = buffer->get(4*len); } - virtual Type getType() const { - return Type::IntArray; + virtual const TagType & getType() const { + return Type; } virtual void print(std::ostream& os, const std::string &indent) const { diff --git a/src/NBT/IntTag.hpp b/src/NBT/IntTag.hpp index 6514546..e6babd0 100644 --- a/src/NBT/IntTag.hpp +++ b/src/NBT/IntTag.hpp @@ -37,12 +37,15 @@ private: const uint8_t *ptr; public: + static const MakeType Type; + + IntTag(Buffer *buffer) { ptr = buffer->get(4); } - virtual Type getType() const { - return Type::Int; + virtual const TagType & getType() const { + return Type; } virtual void print(std::ostream& os, const std::string &) const { diff --git a/src/NBT/ListTag.hpp b/src/NBT/ListTag.hpp index d86abdb..7276923 100644 --- a/src/NBT/ListTag.hpp +++ b/src/NBT/ListTag.hpp @@ -34,34 +34,29 @@ namespace MinedMap { namespace NBT { +class ListTag : public Tag, public std::vector> { +private: + const TagType *subtype; -class ListTagBase : public Tag { public: - virtual Type getType() const { - return Type::List; - } + static const MakeType Type; - virtual Type getSubtype() const = 0; -}; + ListTag(Buffer *buffer) { + subtype = &getTypeById(buffer->get8()); -template -class ListTag : public ListTagBase, public std::vector> { -private: - Type type; - -public: - ListTag(Type type0, Buffer *buffer) : type(type0) { uint32_t len = buffer->get32(); - this->resize(len); - for (uint32_t i = 0; i < len; i++) - (*this)[i] = std::static_pointer_cast(Tag::readTag(type, buffer)); + push_back(subtype->read(buffer)); + } + + virtual const TagType & getType() const { + return Type; } - virtual Type getSubtype() const { - return type; + virtual const TagType & getSubtype() const { + return *subtype; } virtual void print(std::ostream& os, const std::string &indent) const { diff --git a/src/NBT/LongArrayTag.hpp b/src/NBT/LongArrayTag.hpp index 1ca3ae6..545798f 100644 --- a/src/NBT/LongArrayTag.hpp +++ b/src/NBT/LongArrayTag.hpp @@ -40,13 +40,16 @@ private: const uint8_t *ptr; public: + static const MakeType Type; + + LongArrayTag(Buffer *buffer) { len = buffer->get32(); ptr = buffer->get(8*len); } - virtual Type getType() const { - return Type::LongArray; + virtual const TagType & getType() const { + return Type; } virtual void print(std::ostream& os, const std::string &indent) const { diff --git a/src/NBT/LongTag.hpp b/src/NBT/LongTag.hpp index f600d8e..05f6bc2 100644 --- a/src/NBT/LongTag.hpp +++ b/src/NBT/LongTag.hpp @@ -37,12 +37,15 @@ private: const uint8_t *ptr; public: + static const MakeType Type; + + LongTag(Buffer *buffer) { ptr = buffer->get(8); } - virtual Type getType() const { - return Type::Long; + virtual const TagType & getType() const { + return Type; } virtual void print(std::ostream& os, const std::string &) const { diff --git a/src/NBT/ShortTag.hpp b/src/NBT/ShortTag.hpp index c66dc05..593a1ed 100644 --- a/src/NBT/ShortTag.hpp +++ b/src/NBT/ShortTag.hpp @@ -37,12 +37,15 @@ private: const uint8_t *ptr; public: + static const MakeType Type; + + ShortTag(Buffer *buffer) { ptr = buffer->get(2); } - virtual Type getType() const { - return Type::Short; + virtual const TagType & getType() const { + return Type; } virtual void print(std::ostream& os, const std::string &) const { diff --git a/src/NBT/StringTag.hpp b/src/NBT/StringTag.hpp index 2fda6d3..8672b73 100644 --- a/src/NBT/StringTag.hpp +++ b/src/NBT/StringTag.hpp @@ -38,13 +38,16 @@ private: const uint8_t *ptr; public: + static const MakeType Type; + + StringTag(Buffer *buffer) { len = buffer->get16(); ptr = buffer->get(len); } - virtual Type getType() const { - return Type::String; + virtual const TagType & getType() const { + return Type; } virtual void print(std::ostream& os, const std::string &) const { diff --git a/src/NBT/Tag.cpp b/src/NBT/Tag.cpp index 31f1420..e8c429f 100644 --- a/src/NBT/Tag.cpp +++ b/src/NBT/Tag.cpp @@ -41,176 +41,50 @@ #include "LongArrayTag.hpp" -#include - - namespace MinedMap { namespace NBT { -std::shared_ptr Tag::readTag(Type type, Buffer *buffer) { - switch (type) { - case Type::End: - return std::make_shared(); - - case Type::Byte: - return std::make_shared(buffer); - - case Type::Short: - return std::make_shared(buffer); - - case Type::Int: - return std::make_shared(buffer); - - case Type::Long: - return std::make_shared(buffer); - - case Type::Float: - return std::make_shared(buffer); - - case Type::Double: - return std::make_shared(buffer); - - case Type::ByteArray: - return std::make_shared(buffer); - - case Type::String: - return std::make_shared(buffer); - - case Type::List: - return readList(buffer); - - case Type::Compound: - return std::make_shared(buffer); - - case Type::IntArray: - return std::make_shared(buffer); - - case Type::LongArray: - return std::make_shared(buffer); - - default: - throw std::runtime_error("Tag::readTag: unknown tag type"); - } -} - -std::shared_ptr Tag::readList(Buffer *buffer) { - Type type = static_cast(buffer->get8()); - - switch (type) { - case Type::End: - return std::make_shared>(type, buffer); - - case Type::Byte: - return std::make_shared>(type, buffer); - - case Type::Short: - return std::make_shared>(type, buffer); - - case Type::Int: - return std::make_shared>(type, buffer); - - case Type::Long: - return std::make_shared>(type, buffer); - - case Type::Float: - return std::make_shared>(type, buffer); - - case Type::Double: - return std::make_shared>(type, buffer); +const Tag::MakeType EndTag::Type("End"); +const Tag::MakeType ByteTag::Type("Byte"); +const Tag::MakeType ShortTag::Type("Short"); +const Tag::MakeType IntTag::Type("Int"); +const Tag::MakeType LongTag::Type("Long"); +const Tag::MakeType FloatTag::Type("Float"); +const Tag::MakeType DoubleTag::Type("Double"); +const Tag::MakeType ByteArrayTag::Type("ByteArray"); +const Tag::MakeType StringTag::Type("String"); +const Tag::MakeType ListTag::Type("List"); +const Tag::MakeType CompoundTag::Type("Compound"); +const Tag::MakeType IntArrayTag::Type("IntArray"); +const Tag::MakeType LongArrayTag::Type("LongArray"); + + +const std::vector Tag::types = { + &EndTag::Type, + &ByteTag::Type, + &ShortTag::Type, + &IntTag::Type, + &LongTag::Type, + &FloatTag::Type, + &DoubleTag::Type, + &ByteArrayTag::Type, + &StringTag::Type, + &ListTag::Type, + &CompoundTag::Type, + &IntArrayTag::Type, + &LongArrayTag::Type, +}; - case Type::ByteArray: - return std::make_shared>(type, buffer); - - case Type::String: - return std::make_shared>(type, buffer); - - case Type::List: - return std::make_shared>(type, buffer); - - case Type::Compound: - return std::make_shared>(type, buffer); - - case Type::IntArray: - return std::make_shared>(type, buffer); - - case Type::LongArray: - return std::make_shared>(type, buffer); - - default: - throw std::runtime_error("Tag::readList: unknown tag type"); - } -} std::pair> Tag::readNamedTag(Buffer *buffer) { - Type type = static_cast(buffer->get8()); - if (type == Type::End) - return std::make_pair("", std::shared_ptr(new EndTag())); + const TagType &type = getTypeById(buffer->get8()); + if (type == EndTag::Type) + return std::make_pair("", std::make_shared(buffer)); uint16_t len = buffer->get16(); std::string name(reinterpret_cast(buffer->get(len)), len); - return std::make_pair(name, readTag(type, buffer)); -} - -std::ostream& operator<<(std::ostream& os, Tag::Type type) { - switch (type) { - case Tag::Type::End: - os << "End"; - break; - - case Tag::Type::Byte: - os << "Byte"; - break; - - case Tag::Type::Short: - os << "Short"; - break; - - case Tag::Type::Int: - os << "Int"; - break; - - case Tag::Type::Long: - os << "Long"; - break; - - case Tag::Type::Float: - os << "Float"; - break; - - case Tag::Type::Double: - os << "Double"; - break; - - case Tag::Type::ByteArray: - os << "ByteArray"; - break; - - case Tag::Type::String: - os << "String"; - break; - - case Tag::Type::List: - os << "List"; - break; - - case Tag::Type::Compound: - os << "Compound"; - break; - - case Tag::Type::IntArray: - os << "IntArray"; - break; - - case Tag::Type::LongArray: - os << "LongArray"; - break; - - default: - os.setstate(std::ios_base::failbit); - } - - return os; + return std::make_pair(name, type.read(buffer)); } } diff --git a/src/NBT/Tag.hpp b/src/NBT/Tag.hpp index b0c20af..3fb824b 100644 --- a/src/NBT/Tag.hpp +++ b/src/NBT/Tag.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "../Buffer.hpp" @@ -36,37 +37,61 @@ namespace MinedMap { namespace NBT { +class Tag; + +class TagType { +public: + TagType() = default; + TagType(const TagType&) = delete; + TagType & operator=(const TagType&) = delete; + + virtual const char * getName() const = 0; + virtual std::shared_ptr read(Buffer *buffer) const = 0; + + bool operator==(const TagType &type) const { + return this == &type; + } +}; + class Tag { private: - static std::shared_ptr readList(Buffer *buffer); + static const std::vector types; -public: - enum class Type { - End = 0, - Byte = 1, - Short = 2, - Int = 3, - Long = 4, - Float = 5, - Double = 6, - ByteArray = 7, - String = 8, - List = 9, - Compound = 10, - IntArray = 11, - LongArray = 12, +protected: + template + class MakeType : public TagType { + private: + const char *name; + + public: + MakeType(const char *name0) : name(name0) {} + + virtual const char * getName() const { + return name; + } + + virtual std::shared_ptr read(Buffer *buffer) const { + return std::make_shared(buffer); + } }; - static std::shared_ptr readTag(Type type, Buffer *buffer); + + static const TagType & getTypeById(uint8_t id) { + return *types.at(id); + } + +public: static std::pair> readNamedTag(Buffer *buffer); - virtual Type getType() const = 0; + virtual const TagType & getType() const = 0; virtual void print(std::ostream& os, const std::string &indent) const = 0; virtual ~Tag() {} }; -std::ostream& operator<<(std::ostream& os, Tag::Type type); +static inline std::ostream& operator<<(std::ostream& os, const TagType &type) { + return os << type.getName(); +} static inline std::ostream& operator<<(std::ostream& os, const Tag &tag) { os << tag.getType() << " "; diff --git a/src/World/Chunk.cpp b/src/World/Chunk.cpp index 07e38a4..38ca496 100644 --- a/src/World/Chunk.cpp +++ b/src/World/Chunk.cpp @@ -44,8 +44,9 @@ Chunk::Chunk(const ChunkData *data) { std::shared_ptr lightPopulatedTag = level->get("LightPopulated"); bool lightPopulated = lightPopulatedTag && lightPopulatedTag->getValue(); - sections = assertValue(level->get>("Sections")); - maxY = (assertValue(sections->back()->get("Y"))->getValue() + 1) * SIZE; + sections = assertValue(level->get("Sections")); + const NBT::CompoundTag *lastSection = assertValue(dynamic_cast(sections->back().get())); + maxY = (assertValue(lastSection->get("Y"))->getValue() + 1) * SIZE; std::shared_ptr biomeTag = assertValue(level->get("Biomes")); @@ -65,7 +66,8 @@ Chunk::Chunk(const ChunkData *data) { std::memset(blockBlockLight.get(), 0, maxY * SIZE * SIZE / 2); - for (auto §ion : *sections) { + for (auto §ionTag : *sections) { + const NBT::CompoundTag *section = assertValue(dynamic_cast(sectionTag.get())); std::shared_ptr blocks = assertValue(section->get("Blocks")); std::shared_ptr data = assertValue(section->get("Data")); size_t Y = assertValue(section->get("Y"))->getValue(); diff --git a/src/World/Chunk.hpp b/src/World/Chunk.hpp index d4213b3..4bd301d 100644 --- a/src/World/Chunk.hpp +++ b/src/World/Chunk.hpp @@ -52,7 +52,7 @@ public: private: std::shared_ptr level; - std::shared_ptr> sections; + std::shared_ptr sections; unsigned maxY; @@ -107,7 +107,7 @@ public: return *level; } - const NBT::ListTag & getSections() const { + const NBT::ListTag & getSections() const { return *sections; } -- cgit v1.2.3