Basic foundation for Block registry

This commit is contained in:
Alpyne 2020-11-06 17:51:08 -08:00
parent 6584a2c022
commit b722c5530c
8 changed files with 182 additions and 10 deletions

19
src/block/Block.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include <string>
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; }
};
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "Common.h"
#include <string>
#include <string_view>
#include <functional>
@ -8,6 +9,7 @@
namespace Feather
{
// Represents the state data of a particular instance of a Block
class BlockState
{
friend struct std::hash<BlockState>;

View File

@ -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<BlockState> Registry::BLOCK_STATES;
RegistryMap<Block> 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<StringBuffer> writer(buf);

View File

@ -1,14 +1,21 @@
#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<Block> BLOCKS;
// Maps numeric ID to BlockState
static IDMapper<BlockState> BLOCK_STATES;
static void Init();

42
src/data/RegistryMap.h Normal file
View File

@ -0,0 +1,42 @@
#pragma once
#include "resources/Identifier.h"
#include <map>
namespace Feather
{
// Registry that maps Identifiers to objects
// TODO: optimize ownership (move, forward, copying, etc). perhaps use pointers
template <class T>
class RegistryMap
{
std::map<Identifier, T> 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 T>
class DefaultedRegistry : public RegistryMap<T>
{
using string = std::string;
const Identifier defaultKey;
T& defaultValue;
public:
DefaultedRegistry(const string&& defaultKey) : defaultKey(Identifier(defaultKey)) {}
};
}

View File

@ -0,0 +1,93 @@
#pragma once
#include "Common.h"
#include <string>
#include <string_view>
#include <ostream>
#include <cctype>
#include <algorithm>
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<Feather::Identifier>
{
size_t operator()(const Feather::Identifier& id) const
{
using std::hash;
using std::string_view;
// based on Mojang's ResourceLocation.hashCode()
return 31 * hash<string_view>{}(id.GetNamespace()) + hash<string_view>{}(id.GetPath());
}
};

View File

@ -16,6 +16,7 @@ using std::stringstream;
namespace Feather
{
// TODO: move this to ChunkSection
const GlobalPalette<BlockState> World::GLOBAL_PALETTE = GlobalPalette<BlockState>(
Registry::BLOCK_STATES,
new BlockState("minecraft:air") // temp

View File

@ -29,6 +29,7 @@ namespace Feather
void PrepareSpawn();
// global palette of all block states
// TODO: move this to ChunkSection
static const GlobalPalette<BlockState> GLOBAL_PALETTE;
Chunk* GetChunk(ChunkPos pos);