diff options
Diffstat (limited to 'game/shared/world')
| -rw-r--r-- | game/shared/world/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | game/shared/world/feature.cc | 28 | ||||
| -rw-r--r-- | game/shared/world/feature.hh | 2 | ||||
| -rw-r--r-- | game/shared/world/item_registry.cc | 9 | ||||
| -rw-r--r-- | game/shared/world/item_registry.hh | 9 | ||||
| -rw-r--r-- | game/shared/world/voxel.cc | 95 | ||||
| -rw-r--r-- | game/shared/world/voxel.hh | 130 | ||||
| -rw-r--r-- | game/shared/world/voxel_registry.cc | 22 | ||||
| -rw-r--r-- | game/shared/world/voxel_registry.hh | 4 | ||||
| -rw-r--r-- | game/shared/world/voxels/generic.hh | 27 |
10 files changed, 223 insertions, 107 deletions
diff --git a/game/shared/world/CMakeLists.txt b/game/shared/world/CMakeLists.txt index 15d5b59..cc7ed90 100644 --- a/game/shared/world/CMakeLists.txt +++ b/game/shared/world/CMakeLists.txt @@ -13,4 +13,6 @@ target_sources(shared PRIVATE "${CMAKE_CURRENT_LIST_DIR}/voxel_registry.cc" "${CMAKE_CURRENT_LIST_DIR}/voxel_registry.hh" "${CMAKE_CURRENT_LIST_DIR}/voxel_storage.cc" - "${CMAKE_CURRENT_LIST_DIR}/voxel_storage.hh") + "${CMAKE_CURRENT_LIST_DIR}/voxel_storage.hh" + "${CMAKE_CURRENT_LIST_DIR}/voxel.cc" + "${CMAKE_CURRENT_LIST_DIR}/voxel.hh") diff --git a/game/shared/world/feature.cc b/game/shared/world/feature.cc index cbf660e..e704ced 100644 --- a/game/shared/world/feature.cc +++ b/game/shared/world/feature.cc @@ -4,6 +4,7 @@ #include "shared/world/chunk.hh"
#include "shared/world/dimension.hh"
+#include "shared/world/voxel.hh"
#include "shared/coord.hh"
@@ -50,3 +51,30 @@ void world::Feature::place(const voxel_pos& vpos, const chunk_pos& cpos, Chunk& }
}
}
+
+void world::Feature::place(const voxel_pos& vpos, const chunk_pos& cpos, VoxelStorage& voxels) const
+{
+ for(const auto [rpos, voxel, overwrite] : (*this)) {
+ auto it_vpos = vpos + rpos;
+ auto it_cpos = coord::to_chunk(it_vpos);
+
+ if(it_cpos == cpos) {
+ auto it_lpos = coord::to_local(it_vpos);
+ auto it_index = coord::to_index(it_lpos);
+
+ if(voxels[it_index] && !overwrite) {
+ // There is something in the way
+ // and the called intentionally requested
+ // we do not force feature to overwrite voxels
+ continue;
+ }
+
+ if(voxel == nullptr) {
+ voxels[it_index] = NULL_VOXEL_ID;
+ }
+ else {
+ voxels[it_index] = voxel->get_id();
+ }
+ }
+ }
+}
diff --git a/game/shared/world/feature.hh b/game/shared/world/feature.hh index 09b913e..a543632 100644 --- a/game/shared/world/feature.hh +++ b/game/shared/world/feature.hh @@ -7,6 +7,7 @@ namespace world class Chunk;
class Dimension;
class Voxel;
+class VoxelStorage;
} // namespace world
namespace world
@@ -19,5 +20,6 @@ public: public:
void place(const voxel_pos& vpos, Dimension* dimension) const;
void place(const voxel_pos& vpos, const chunk_pos& cpos, Chunk& chunk) const;
+ void place(const voxel_pos& vpos, const chunk_pos& cpos, VoxelStorage& voxels) const;
};
} // namespace world
diff --git a/game/shared/world/item_registry.cc b/game/shared/world/item_registry.cc index d1b9ff4..783c85e 100644 --- a/game/shared/world/item_registry.cc +++ b/game/shared/world/item_registry.cc @@ -14,7 +14,7 @@ world::ItemInfoBuilder::ItemInfoBuilder(std::string_view name) {
prototype.name = name;
prototype.texture = std::string();
- prototype.place_voxel = NULL_VOXEL_ID;
+ prototype.place_voxel = nullptr;
prototype.cached_texture = nullptr;
}
@@ -25,7 +25,7 @@ world::ItemInfoBuilder& world::ItemInfoBuilder::set_texture(std::string_view tex return *this;
}
-world::ItemInfoBuilder& world::ItemInfoBuilder::set_place_voxel(voxel_id place_voxel)
+world::ItemInfoBuilder& world::ItemInfoBuilder::set_place_voxel(const Voxel* place_voxel)
{
prototype.place_voxel = place_voxel;
return *this;
@@ -99,7 +99,10 @@ std::uint64_t world::item_registry::calculate_checksum(void) for(const auto& info : world::item_registry::items) {
result = math::crc64(info->name, result);
- result += static_cast<std::uint64_t>(info->place_voxel);
+
+ if(info->place_voxel) {
+ result += static_cast<std::uint64_t>(info->place_voxel->get_id());
+ }
}
return result;
diff --git a/game/shared/world/item_registry.hh b/game/shared/world/item_registry.hh index c3e6cf9..2274da2 100644 --- a/game/shared/world/item_registry.hh +++ b/game/shared/world/item_registry.hh @@ -11,10 +11,15 @@ struct TextureGUI; namespace world
{
+class Voxel;
+} // namespace world
+
+namespace world
+{
struct ItemInfo final {
std::string name;
std::string texture;
- voxel_id place_voxel;
+ const Voxel* place_voxel;
resource_ptr<TextureGUI> cached_texture; // Client-side only
};
@@ -29,7 +34,7 @@ public: public:
ItemInfoBuilder& set_texture(std::string_view texture);
- ItemInfoBuilder& set_place_voxel(voxel_id place_voxel);
+ ItemInfoBuilder& set_place_voxel(const Voxel* place_voxel);
public:
item_id build(void) const;
diff --git a/game/shared/world/voxel.cc b/game/shared/world/voxel.cc index d51b5a1..1cd1504 100644 --- a/game/shared/world/voxel.cc +++ b/game/shared/world/voxel.cc @@ -6,24 +6,30 @@ #include "shared/world/dimension.hh" -void world::Voxel::on_place(Dimension* dimension, const voxel_pos& vpos) const +world::Voxel::Voxel(const Voxel& source, voxel_id id) noexcept : Voxel(source) { - // empty + m_id = id; } -void world::Voxel::on_remove(Dimension* dimension, const voxel_pos& vpos) const +void world::Voxel::on_place(Dimension* dimension, const voxel_pos& vpos) const { - // empty + if(m_on_place) { + m_on_place(dimension, vpos); + } } -void world::Voxel::on_tick(Dimension* dimension, const voxel_pos& vpos) const +void world::Voxel::on_remove(Dimension* dimension, const voxel_pos& vpos) const { - // empty + if(m_on_remove) { + m_on_remove(dimension, vpos); + } } -void world::Voxel::set_id(voxel_id id) noexcept +void world::Voxel::on_tick(Dimension* dimension, const voxel_pos& vpos) const { - m_id = id; + if(m_on_tick) { + m_on_tick(dimension, vpos); + } } std::size_t world::Voxel::get_random_texture_index(VoxelFace face, const voxel_pos& vpos) const @@ -57,64 +63,113 @@ std::uint64_t world::Voxel::calculate_checksum(std::uint64_t combine) const return combine; } -std::shared_ptr<world::Voxel> world::Voxel::clone(void) const +world::VoxelBuilder::VoxelBuilder(std::string_view name) +{ + set_name(name); +} + +world::VoxelBuilder& world::VoxelBuilder::set_on_place(VoxelOnPlaceFunc func) noexcept +{ + m_on_place = std::move(func); + + return *this; +} + +world::VoxelBuilder& world::VoxelBuilder::set_on_remove(VoxelOnRemoveFunc func) noexcept +{ + m_on_remove = std::move(func); + + return *this; +} + +world::VoxelBuilder& world::VoxelBuilder::set_on_tick(VoxelOnTickFunc func) noexcept { - return std::make_shared<Voxel>(*this); + m_on_tick = std::move(func); + + return *this; } -void world::Voxel::set_name(std::string_view name) noexcept +world::VoxelBuilder& world::VoxelBuilder::set_name(std::string_view name) noexcept { assert(name.size()); m_name = name; + + return *this; } -void world::Voxel::set_render_mode(VoxelRender mode) noexcept +world::VoxelBuilder& world::VoxelBuilder::set_render_mode(VoxelRender mode) noexcept { m_render_mode = mode; + + return *this; } -void world::Voxel::set_shape(VoxelShape shape) noexcept +world::VoxelBuilder& world::VoxelBuilder::set_shape(VoxelShape shape) noexcept { m_shape = shape; + + return *this; } -void world::Voxel::set_animated(bool animated) noexcept +world::VoxelBuilder& world::VoxelBuilder::set_animated(bool animated) noexcept { m_animated = animated; + + return *this; } -void world::Voxel::set_touch_type(VoxelTouch type) noexcept +world::VoxelBuilder& world::VoxelBuilder::set_touch_type(VoxelTouch type) noexcept { m_touch_type = type; + + return *this; } -void world::Voxel::set_touch_values(const glm::fvec3& values) noexcept +world::VoxelBuilder& world::VoxelBuilder::set_touch_values(const glm::fvec3& values) noexcept { m_touch_values = values; + + return *this; } -void world::Voxel::set_surface_material(VoxelMaterial material) noexcept +world::VoxelBuilder& world::VoxelBuilder::set_surface_material(VoxelMaterial material) noexcept { m_surface_material = material; + + return *this; } -void world::Voxel::set_collision(const math::AABBf& box) noexcept +world::VoxelBuilder& world::VoxelBuilder::set_collision(const math::AABBf& box) noexcept { m_collision = box; + + return *this; } -void world::Voxel::add_default_texture(std::string_view path) +world::VoxelBuilder& world::VoxelBuilder::add_default_texture(std::string_view path) { assert(path.size()); m_default_textures.emplace_back(path); + + return *this; } -void world::Voxel::add_face_texture(VoxelFace face, std::string_view path) +world::VoxelBuilder& world::VoxelBuilder::add_face_texture(VoxelFace face, std::string_view path) { assert(face < m_face_textures.size()); assert(path.size()); m_face_textures[face].emplace_back(path); + + return *this; +} + +std::unique_ptr<world::Voxel> world::VoxelBuilder::build(voxel_id id) const +{ + assert(m_name.size()); + assert(id); + + return std::make_unique<Voxel>(*this, id); } diff --git a/game/shared/world/voxel.hh b/game/shared/world/voxel.hh index 0bd83b7..9cc0e4c 100644 --- a/game/shared/world/voxel.hh +++ b/game/shared/world/voxel.hh @@ -11,19 +11,19 @@ class Dimension; namespace world { -enum VoxelRender : unsigned short { +enum VoxelRender : unsigned int { VRENDER_NONE = 0U, ///< The voxel is not rendered at all VRENDER_OPAQUE, ///< The voxel is fully opaque VRENDER_BLEND, ///< The voxel is blended (e.g. water, glass) }; -enum VoxelShape : unsigned short { +enum VoxelShape : unsigned int { VSHAPE_CUBE = 0U, ///< Full cube shape VSHAPE_CROSS, ///< TODO: Cross shape VSHAPE_MODEL, ///< TODO: Custom model shape }; -enum VoxelFace : unsigned short { +enum VoxelFace : unsigned int { VFACE_NORTH = 0U, ///< Positive Z face VFACE_SOUTH, ///< Negative Z face VFACE_EAST, ///< Positive X face @@ -35,14 +35,15 @@ enum VoxelFace : unsigned short { VFACE_COUNT }; -enum VoxelTouch : unsigned short { +enum VoxelTouch : unsigned int { VTOUCH_NONE = 0xFFFFU, VTOUCH_SOLID = 0U, ///< The entity is stopped in its tracks VTOUCH_BOUNCE, ///< The entity bounces back with some energy loss VTOUCH_SINK, ///< The entity phases/sinks through the voxel }; -enum VoxelMaterial : unsigned short { +enum VoxelMaterial : unsigned int { + VMAT_UNKNOWN = 0xFFFFU, VMAT_DEFAULT = 0U, VMAT_STONE, VMAT_DIRT, @@ -56,7 +57,7 @@ enum VoxelMaterial : unsigned short { VMAT_COUNT }; -enum VoxelVisBits : unsigned short { +enum VoxelVisBits : unsigned int { VVIS_NORTH = 1U << VFACE_NORTH, ///< Positive Z VVIS_SOUTH = 1U << VFACE_SOUTH, ///< Negative Z VVIS_EAST = 1U << VFACE_EAST, ///< Positive X @@ -68,26 +69,24 @@ enum VoxelVisBits : unsigned short { namespace world { +using VoxelOnPlaceFunc = std::function<void(Dimension*, const voxel_pos&)>; +using VoxelOnRemoveFunc = std::function<void(Dimension*, const voxel_pos&)>; +using VoxelOnTickFunc = std::function<void(Dimension*, const voxel_pos&)>; +} // namespace world + +namespace world +{ class Voxel { public: - /// Called when the voxel is placed in the world - /// @param dimension The dimension the voxel is placed in - /// @param vpos The absolute voxel position where the voxel is placed - virtual void on_place(Dimension* dimension, const voxel_pos& vpos) const; - - /// Called when the voxel is removed from the world - /// @param dimension The dimension the voxel is removed from - /// @param vpos The absolute voxel position where the voxel is removed - virtual void on_remove(Dimension* dimension, const voxel_pos& vpos) const; + Voxel(void) = default; + explicit Voxel(const Voxel& source, voxel_id id) noexcept; - /// Called when the voxel is ticked by something - /// @param dimension The dimension the voxel is ticked in - /// @param vpos The absolute voxel position where the voxel is ticked - virtual void on_tick(Dimension* dimension, const voxel_pos& vpos) const; + void on_place(Dimension* dimension, const voxel_pos& vpos) const; + void on_remove(Dimension* dimension, const voxel_pos& vpos) const; + void on_tick(Dimension* dimension, const voxel_pos& vpos) const; constexpr std::string_view get_name(void) const noexcept; constexpr voxel_id get_id(void) const noexcept; - void set_id(voxel_id id) noexcept; constexpr VoxelRender get_render_mode(void) const noexcept; constexpr VoxelShape get_shape(void) const noexcept; @@ -104,6 +103,15 @@ public: constexpr std::size_t get_cached_face_offset(VoxelFace face) const noexcept; constexpr std::size_t get_cached_face_plane(VoxelFace face) const noexcept; + template<VoxelRender RenderMode> + constexpr bool is_render_mode(void) const noexcept; + template<VoxelShape Shape> + constexpr bool is_shape(void) const noexcept; + template<VoxelTouch TouchType> + constexpr bool is_touch_type(void) const noexcept; + template<VoxelMaterial Material> + constexpr bool is_surface_material(void) const noexcept; + /// Non-model voxel shapes support texture variation based on the /// voxel position on the world; this method handles the math behind this /// @param face The face of the voxel to get the texture index for @@ -123,27 +131,7 @@ public: /// @return The calculated checksum std::uint64_t calculate_checksum(std::uint64_t combine = 0U) const; - /// Produce a copy of itself as a shared pointer; the voxel registry - /// does not change the owner of a voxel instance it registers - virtual std::shared_ptr<Voxel> clone(void) const; - protected: - void set_name(std::string_view name) noexcept; - - void set_render_mode(VoxelRender mode) noexcept; - void set_shape(VoxelShape shape) noexcept; - void set_animated(bool animated) noexcept; - - void set_touch_type(VoxelTouch type) noexcept; - void set_touch_values(const glm::fvec3& values) noexcept; - void set_surface_material(VoxelMaterial material) noexcept; - - void set_collision(const math::AABBf& box) noexcept; - - void add_default_texture(std::string_view path); - void add_face_texture(VoxelFace face, std::string_view path); - -private: std::string m_name; voxel_id m_id { NULL_VOXEL_ID }; @@ -161,6 +149,40 @@ private: std::array<std::vector<std::string>, VFACE_COUNT> m_face_textures; std::array<std::size_t, VFACE_COUNT> m_cached_face_offsets; std::array<std::size_t, VFACE_COUNT> m_cached_face_planes; + + VoxelOnPlaceFunc m_on_place; + VoxelOnRemoveFunc m_on_remove; + VoxelOnTickFunc m_on_tick; +}; +} // namespace world + +namespace world +{ +class VoxelBuilder final : public Voxel { +public: + VoxelBuilder(void) = default; + explicit VoxelBuilder(std::string_view name); + + VoxelBuilder& set_on_place(VoxelOnPlaceFunc func) noexcept; + VoxelBuilder& set_on_remove(VoxelOnRemoveFunc func) noexcept; + VoxelBuilder& set_on_tick(VoxelOnTickFunc func) noexcept; + + VoxelBuilder& set_name(std::string_view name) noexcept; + + VoxelBuilder& set_render_mode(VoxelRender mode) noexcept; + VoxelBuilder& set_shape(VoxelShape shape) noexcept; + VoxelBuilder& set_animated(bool animated) noexcept; + + VoxelBuilder& set_touch_type(VoxelTouch type) noexcept; + VoxelBuilder& set_touch_values(const glm::fvec3& values) noexcept; + VoxelBuilder& set_surface_material(VoxelMaterial material) noexcept; + + VoxelBuilder& set_collision(const math::AABBf& box) noexcept; + + VoxelBuilder& add_default_texture(std::string_view path); + VoxelBuilder& add_face_texture(VoxelFace face, std::string_view path); + + std::unique_ptr<Voxel> build(voxel_id id) const; }; } // namespace world @@ -218,6 +240,10 @@ constexpr const std::vector<std::string>& world::Voxel::get_face_textures(VoxelF { assert(face <= m_face_textures.size()); + if(m_face_textures[face].empty()) { + return m_default_textures; + } + return m_face_textures[face]; } @@ -234,3 +260,27 @@ constexpr std::size_t world::Voxel::get_cached_face_plane(VoxelFace face) const return m_cached_face_planes[face]; } + +template<world::VoxelRender RenderMode> +constexpr bool world::Voxel::is_render_mode(void) const noexcept +{ + return m_render_mode == RenderMode; +} + +template<world::VoxelShape Shape> +constexpr bool world::Voxel::is_shape(void) const noexcept +{ + return m_shape == Shape; +} + +template<world::VoxelTouch TouchType> +constexpr bool world::Voxel::is_touch_type(void) const noexcept +{ + return m_touch_type == TouchType; +} + +template<world::VoxelMaterial Material> +constexpr bool world::Voxel::is_surface_material(void) const noexcept +{ + return m_surface_material == Material; +} diff --git a/game/shared/world/voxel_registry.cc b/game/shared/world/voxel_registry.cc index 4c2f360..97485e6 100644 --- a/game/shared/world/voxel_registry.cc +++ b/game/shared/world/voxel_registry.cc @@ -4,7 +4,7 @@ static std::uint64_t registry_checksum = 0U;
emhash8::HashMap<std::string, voxel_id> world::voxel_registry::names;
-std::vector<std::shared_ptr<world::Voxel>> world::voxel_registry::voxels;
+std::vector<std::unique_ptr<world::Voxel>> world::voxel_registry::voxels;
static void recalculate_checksum(void)
{
@@ -15,17 +15,15 @@ static void recalculate_checksum(void) }
}
-world::Voxel* world::voxel_registry::register_voxel(const Voxel& voxel_template)
+world::Voxel* world::voxel_registry::register_voxel(const VoxelBuilder& builder)
{
- assert(voxel_template.get_name().size());
- assert(nullptr == find(voxel_template.get_name()));
+ assert(builder.get_name().size());
+ assert(nullptr == find(builder.get_name()));
- const auto id = static_cast<voxel_id>(voxels.size());
+ const auto id = static_cast<voxel_id>(1 + voxels.size());
- auto voxel = voxel_template.clone();
- voxel->set_id(id);
-
- names.emplace(std::string(voxel_template.get_name()), id);
+ std::unique_ptr<Voxel> voxel(builder.build(id));
+ names.emplace(std::string(builder.get_name()), id);
voxels.push_back(std::move(voxel));
recalculate_checksum();
@@ -35,7 +33,7 @@ world::Voxel* world::voxel_registry::register_voxel(const Voxel& voxel_template) world::Voxel* world::voxel_registry::find(std::string_view name)
{
- const auto it = names.find(name);
+ const auto it = names.find(std::string(name));
if(it == names.end()) {
return nullptr;
@@ -46,11 +44,11 @@ world::Voxel* world::voxel_registry::find(std::string_view name) world::Voxel* world::voxel_registry::find(voxel_id id)
{
- if(id >= voxels.size()) {
+ if(id == NULL_VOXEL_ID || id > voxels.size()) {
return nullptr;
}
- return voxels[id].get();
+ return voxels[id - 1].get();
}
void world::voxel_registry::purge(void)
diff --git a/game/shared/world/voxel_registry.hh b/game/shared/world/voxel_registry.hh index b9d9a34..5ba2aed 100644 --- a/game/shared/world/voxel_registry.hh +++ b/game/shared/world/voxel_registry.hh @@ -5,12 +5,12 @@ namespace world::voxel_registry
{
extern emhash8::HashMap<std::string, voxel_id> names;
-extern std::vector<std::shared_ptr<Voxel>> voxels;
+extern std::vector<std::unique_ptr<Voxel>> voxels;
} // namespace world::voxel_registry
namespace world::voxel_registry
{
-Voxel* register_voxel(const Voxel& voxel_template);
+Voxel* register_voxel(const VoxelBuilder& builder);
Voxel* find(std::string_view name);
Voxel* find(voxel_id id);
} // namespace world::voxel_registry
diff --git a/game/shared/world/voxels/generic.hh b/game/shared/world/voxels/generic.hh deleted file mode 100644 index a661792..0000000 --- a/game/shared/world/voxels/generic.hh +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "shared/world/voxel.hh" - -namespace world::voxels -{ -class GenericCube final : public Voxel { -public: - template<typename... TexturesT> - requires(std::is_convertible_v<TexturesT, std::string_view> && ...) - explicit GenericCube(std::string_view name, VoxelRender render_mode, bool animated, VoxelMaterial surface_material, VoxelTouch touch, - const glm::fvec3& touch_values, TexturesT&&... textures) noexcept - { - set_name(name); - - set_shape(VoxelShape::CUBE); - set_render_mode(render_mode); - set_animated(animated); - - set_surface_material(surface_material); - set_touch_values(touch_values); - set_touch_type(touch); - - add_texture_default(std::forward<TexturesT>(textures)...); - } -}; -} // namespace world::voxels |
