From b722c5530cc581e06be49207de41dfcdbf2090dc Mon Sep 17 00:00:00 2001 From: Alpyne Date: Fri, 6 Nov 2020 17:51:08 -0800 Subject: [PATCH] Basic foundation for Block registry --- src/block/Block.h | 19 ++++++++ src/block/state/BlockState.h | 4 +- src/data/Registry.cpp | 23 +++++---- src/data/Registry.h | 9 +++- src/data/RegistryMap.h | 42 ++++++++++++++++ src/resources/Identifier.h | 93 ++++++++++++++++++++++++++++++++++++ src/world/World.cpp | 1 + src/world/World.h | 1 + 8 files changed, 182 insertions(+), 10 deletions(-) create mode 100644 src/block/Block.h create mode 100644 src/data/RegistryMap.h create mode 100644 src/resources/Identifier.h diff --git a/src/block/Block.h b/src/block/Block.h new file mode 100644 index 0000000..6c33e23 --- /dev/null +++ b/src/block/Block.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace Feather +{ + // Represents a type of block and its behavior. + class Block + { + using string = std::string; + + const Identifier m_id; + + public: + Block(string&& name) : m_id(name) {} + + inline const Identifier& GetIdentifier() const { return m_id; } + }; +} diff --git a/src/block/state/BlockState.h b/src/block/state/BlockState.h index d6bc0d6..36826ab 100644 --- a/src/block/state/BlockState.h +++ b/src/block/state/BlockState.h @@ -1,6 +1,7 @@ #pragma once #include "Common.h" + #include #include #include @@ -8,6 +9,7 @@ namespace Feather { + // Represents the state data of a particular instance of a Block class BlockState { friend struct std::hash; @@ -54,4 +56,4 @@ struct std::hash return accum; } -}; \ No newline at end of file +}; diff --git a/src/data/Registry.cpp b/src/data/Registry.cpp index 085f6c8..0d9a770 100644 --- a/src/data/Registry.cpp +++ b/src/data/Registry.cpp @@ -1,5 +1,6 @@ #include "Common.h" #include "Registry.h" +#include "block/Block.h" #include "rapidjson/document.h" #include "rapidjson/filereadstream.h" @@ -14,6 +15,7 @@ namespace Feather { IDMapper Registry::BLOCK_STATES; + RegistryMap Registry::BLOCKS; void Registry::Init() { @@ -40,15 +42,18 @@ namespace Feather doc.Parse(text.c_str()); - for (auto& block : doc.GetObject()) + for (auto& blockData : doc.GetObject()) { - // TODO - //if (block.value.HasMember("properties")) {} + const char* blockName = blockData.name.GetString(); + Block block(blockName); - //Log::Info("{}: {} states", block.name.GetString(), block.value["states"].Size()); - for (auto& stateData : block.value["states"].GetArray()) + // TODO + //if (blockData.value.HasMember("properties")) {} + + //Log::Info("{}: {} states", blockData.name.GetString(), blockData.value["states"].Size()); + for (auto& stateData : blockData.value["states"].GetArray()) { - std::string* name = new std::string(block.name.GetString()); + std::string* name = new std::string(blockName); BlockState state(*name); if (stateData.HasMember("properties")) @@ -64,9 +69,11 @@ namespace Feather BLOCK_STATES.AddMapping(stateData["id"].GetInt(), state); } + BLOCKS.Register(block.GetIdentifier(), std::move(block)); + } - Log::Info("Loaded {} block states.", BLOCK_STATES.Size()); + Log::Info("Loaded {} blocks and {} block states.", BLOCKS.Size(), BLOCK_STATES.Size()); //StringBuffer buf; //Writer writer(buf); @@ -79,4 +86,4 @@ namespace Feather } } -} \ No newline at end of file +} diff --git a/src/data/Registry.h b/src/data/Registry.h index d0c4215..33280ba 100644 --- a/src/data/Registry.h +++ b/src/data/Registry.h @@ -1,16 +1,23 @@ #pragma once #include "IDMapper.h" +#include "RegistryMap.h" #include "block/state/BlockState.h" namespace Feather { + class Block; + class Registry { public: + // Maps block Identifier to Block + static RegistryMap BLOCKS; + + // Maps numeric ID to BlockState static IDMapper BLOCK_STATES; static void Init(); }; -} \ No newline at end of file +} diff --git a/src/data/RegistryMap.h b/src/data/RegistryMap.h new file mode 100644 index 0000000..f516d12 --- /dev/null +++ b/src/data/RegistryMap.h @@ -0,0 +1,42 @@ +#pragma once + +#include "resources/Identifier.h" + +#include + +namespace Feather +{ + // Registry that maps Identifiers to objects + // TODO: optimize ownership (move, forward, copying, etc). perhaps use pointers + template + class RegistryMap + { + std::map map; + + public: + inline void Register(const Identifier& id, T&& value) + { + map.insert({ id, std::move(value) }); + } + + inline const T& Get(const Identifier& id) const { return map.at(id); } + + //inline Identifier& GetKey(T& value) const {} + + inline size_t Size() const { return map.size(); } + }; + + template + class DefaultedRegistry : public RegistryMap + { + using string = std::string; + + const Identifier defaultKey; + T& defaultValue; + + public: + DefaultedRegistry(const string&& defaultKey) : defaultKey(Identifier(defaultKey)) {} + + + }; +} diff --git a/src/resources/Identifier.h b/src/resources/Identifier.h new file mode 100644 index 0000000..799023f --- /dev/null +++ b/src/resources/Identifier.h @@ -0,0 +1,93 @@ +#pragma once + +#include "Common.h" + +#include +#include +#include +#include +#include + +namespace Feather +{ + // Namespaced ID, like "minecraft:lily_pad", also known as ResourceLocation + class Identifier + { + using string = std::string; + using string_view = std::string_view; + + protected: + const string m_namespace; + const string m_path; + + public: + inline static const string_view DEFAULT_NAMESPACE = "minecraft"; + inline static const char SEPARATOR = ':'; + + + Identifier(const string&& ns, const string&& path) : + m_namespace(ns.empty() ? DEFAULT_NAMESPACE : ns), + m_path(path) + { + Assert(IsValidNamespace(m_namespace), "Identifier namespace contains non [a-z0-9_.-] character: {}", m_namespace); + Assert(IsValidPath(m_path), "Identifier path contains non [a-z0-9/._-] character: {}", m_path); + } + + Identifier(const string& id) : Identifier(id, id.find(SEPARATOR)) {} + + inline const string_view& GetNamespace() const { return m_namespace; } + inline const string_view& GetPath() const { return m_path; } + + + + // Operators + + inline bool operator==(const Identifier& id) const { return this == &id || (m_namespace == id.m_namespace && m_path == id.m_path); } + + inline bool operator<(const Identifier& id) const { return this != &id && (m_path < id.m_path || m_namespace < id.m_namespace); } + + friend inline std::ostream& operator<<(std::ostream& st, const Identifier& id) + { + return st << id.m_namespace.data() << ":" << id.m_path.data(); + } + protected: + + // Construct an Identifier having found the separator character, if any + Identifier(const string& id, const size_t split) : Identifier( + split == string::npos ? "" : id.substr(0, split), + split == string::npos ? id : id.substr(split + 1)) + {} + + // Identifiers: 0-9 a-z _ : / . - + inline static bool AllowedChar(char c) + { + return ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || c == '_' || c == ':' || c == '/' || c == '.' || c == '-'; + } + + // Paths cannot contain : + inline static bool IsValidPath(const string& ns) + { + return std::all_of(ns.begin(), ns.end(), [](char c) { return AllowedChar(c) && c != ':'; }); + } + + // Namespaces cannot contain : or / + inline static bool IsValidNamespace(const string& ns) + { + return std::all_of(ns.begin(), ns.end(), [](char c) { return AllowedChar(c) && c != '/' && c != ':'; }); + } + }; +} + +template <> +struct std::hash +{ + size_t operator()(const Feather::Identifier& id) const + { + using std::hash; + using std::string_view; + + // based on Mojang's ResourceLocation.hashCode() + return 31 * hash{}(id.GetNamespace()) + hash{}(id.GetPath()); + } +}; + diff --git a/src/world/World.cpp b/src/world/World.cpp index a42e893..347b4b1 100644 --- a/src/world/World.cpp +++ b/src/world/World.cpp @@ -16,6 +16,7 @@ using std::stringstream; namespace Feather { + // TODO: move this to ChunkSection const GlobalPalette World::GLOBAL_PALETTE = GlobalPalette( Registry::BLOCK_STATES, new BlockState("minecraft:air") // temp diff --git a/src/world/World.h b/src/world/World.h index ad77a51..5eb55d4 100644 --- a/src/world/World.h +++ b/src/world/World.h @@ -29,6 +29,7 @@ namespace Feather void PrepareSpawn(); // global palette of all block states + // TODO: move this to ChunkSection static const GlobalPalette GLOBAL_PALETTE; Chunk* GetChunk(ChunkPos pos);