From 73cbcdd6e8c849e32abbf9757e603e6a6654e870 Mon Sep 17 00:00:00 2001 From: untodesu Date: Fri, 12 Sep 2025 14:09:34 +0500 Subject: Metaitems --- game/shared/world/CMakeLists.txt | 2 + game/shared/world/chunk.cc | 7 +-- game/shared/world/feature.cc | 7 +-- game/shared/world/item.cc | 55 ++++++++++++++++++++ game/shared/world/item.hh | 84 ++++++++++++++++++++++++++++++ game/shared/world/item_registry.cc | 101 +++++++++++------------------------- game/shared/world/item_registry.hh | 55 +++----------------- game/shared/world/voxel.cc | 54 +++++-------------- game/shared/world/voxel.hh | 28 +++++----- game/shared/world/voxel_registry.cc | 4 +- 10 files changed, 209 insertions(+), 188 deletions(-) create mode 100644 game/shared/world/item.cc create mode 100644 game/shared/world/item.hh (limited to 'game/shared/world') diff --git a/game/shared/world/CMakeLists.txt b/game/shared/world/CMakeLists.txt index cc7ed90..db3f370 100644 --- a/game/shared/world/CMakeLists.txt +++ b/game/shared/world/CMakeLists.txt @@ -8,6 +8,8 @@ target_sources(shared PRIVATE "${CMAKE_CURRENT_LIST_DIR}/feature.hh" "${CMAKE_CURRENT_LIST_DIR}/item_registry.cc" "${CMAKE_CURRENT_LIST_DIR}/item_registry.hh" + "${CMAKE_CURRENT_LIST_DIR}/item.cc" + "${CMAKE_CURRENT_LIST_DIR}/item.hh" "${CMAKE_CURRENT_LIST_DIR}/ray_dda.cc" "${CMAKE_CURRENT_LIST_DIR}/ray_dda.hh" "${CMAKE_CURRENT_LIST_DIR}/voxel_registry.cc" diff --git a/game/shared/world/chunk.cc b/game/shared/world/chunk.cc index b1b19a6..f8f7b93 100644 --- a/game/shared/world/chunk.cc +++ b/game/shared/world/chunk.cc @@ -36,12 +36,7 @@ void world::Chunk::set_voxel(const Voxel* voxel, const local_pos& lpos) void world::Chunk::set_voxel(const Voxel* voxel, const std::size_t index) { if(index < CHUNK_VOLUME) { - if(voxel == nullptr) { - m_voxels[index] = NULL_VOXEL_ID; - return; - } - - m_voxels[index] = voxel->get_id(); + m_voxels[index] = voxel ? voxel->get_id() : NULL_VOXEL_ID; return; } } diff --git a/game/shared/world/feature.cc b/game/shared/world/feature.cc index e704ced..8fe95f1 100644 --- a/game/shared/world/feature.cc +++ b/game/shared/world/feature.cc @@ -69,12 +69,7 @@ void world::Feature::place(const voxel_pos& vpos, const chunk_pos& cpos, VoxelSt continue; } - if(voxel == nullptr) { - voxels[it_index] = NULL_VOXEL_ID; - } - else { - voxels[it_index] = voxel->get_id(); - } + voxels[it_index] = voxel ? voxel->get_id() : NULL_VOXEL_ID; } } } diff --git a/game/shared/world/item.cc b/game/shared/world/item.cc new file mode 100644 index 0000000..5e60609 --- /dev/null +++ b/game/shared/world/item.cc @@ -0,0 +1,55 @@ +#include "shared/pch.hh" + +#include "shared/world/item.hh" + +#include "core/math/crc64.hh" + +#include "shared/world/voxel.hh" + +world::Item::Item(const Item& source, item_id id) noexcept : Item(source) +{ + m_id = id; +} + +void world::Item::set_cached_texture(resource_ptr texture) const noexcept +{ + m_cached_texture = std::move(texture); +} + +std::uint64_t world::Item::get_checksum(std::uint64_t combine) const +{ + combine = math::crc64(m_name.data(), m_name.size(), combine); + combine = math::crc64(m_texture.data(), m_texture.size(), combine); + + std::uint32_t id = m_place_voxel ? m_place_voxel->get_id() : NULL_VOXEL_ID; + combine = math::crc64(&id, sizeof(id), combine); + + return combine; +} + +world::ItemBuilder::ItemBuilder(std::string_view name) +{ + set_name(name); +} + +void world::ItemBuilder::set_name(std::string_view name) +{ + assert(name.size()); + + m_name = name; +} + +void world::ItemBuilder::set_texture(std::string_view texture) +{ + m_texture = texture; +} + +void world::ItemBuilder::set_place_voxel(const Voxel* place_voxel) +{ + m_place_voxel = place_voxel; +} + +std::unique_ptr world::ItemBuilder::build(item_id id) const +{ + return std::make_unique(*this, id); +} diff --git a/game/shared/world/item.hh b/game/shared/world/item.hh new file mode 100644 index 0000000..ffa7f5c --- /dev/null +++ b/game/shared/world/item.hh @@ -0,0 +1,84 @@ +#pragma once + +#include "core/resource/resource.hh" + +#include "shared/types.hh" + +// This resource is only defined client-side and +// resource_ptr should remain set to null +// anywhere else in the shared and server code +struct TextureGUI; + +namespace world +{ +class Voxel; +} // namespace world + +namespace world +{ +class Item { +public: + Item(void) = default; + explicit Item(const Item& source, item_id id) noexcept; + + constexpr std::string_view get_name(void) const noexcept; + constexpr item_id get_id(void) const noexcept; + + constexpr std::string_view get_texture(void) const noexcept; + constexpr const Voxel* get_place_voxel(void) const noexcept; + + constexpr resource_ptr& get_cached_texture(void) const noexcept; + void set_cached_texture(resource_ptr texture) const noexcept; + + std::uint64_t get_checksum(std::uint64_t combine = 0U) const; + +protected: + std::string m_name; + item_id m_id { NULL_ITEM_ID }; + + std::string m_texture; + const Voxel* m_place_voxel { nullptr }; + + mutable resource_ptr m_cached_texture; // Client-side only +}; +} // namespace world + +namespace world +{ +class ItemBuilder final : public Item { +public: + explicit ItemBuilder(std::string_view name); + + void set_name(std::string_view name); + + void set_texture(std::string_view texture); + void set_place_voxel(const Voxel* place_voxel); + + std::unique_ptr build(item_id id) const; +}; +} // namespace world + +constexpr std::string_view world::Item::get_name(void) const noexcept +{ + return m_name; +} + +constexpr item_id world::Item::get_id(void) const noexcept +{ + return m_id; +} + +constexpr std::string_view world::Item::get_texture(void) const noexcept +{ + return m_texture; +} + +constexpr const world::Voxel* world::Item::get_place_voxel(void) const noexcept +{ + return m_place_voxel; +} + +constexpr resource_ptr& world::Item::get_cached_texture(void) const noexcept +{ + return m_cached_texture; +} diff --git a/game/shared/world/item_registry.cc b/game/shared/world/item_registry.cc index 783c85e..4e0932c 100644 --- a/game/shared/world/item_registry.cc +++ b/game/shared/world/item_registry.cc @@ -6,104 +6,63 @@ #include "shared/world/voxel_registry.hh" -std::unordered_map world::item_registry::builders = {}; +static std::uint64_t registry_checksum = 0U; std::unordered_map world::item_registry::names = {}; -std::vector> world::item_registry::items = {}; +std::vector> world::item_registry::items = {}; -world::ItemInfoBuilder::ItemInfoBuilder(std::string_view name) +static void recalculate_checksum(void) { - prototype.name = name; - prototype.texture = std::string(); - prototype.place_voxel = nullptr; - prototype.cached_texture = nullptr; -} + registry_checksum = 0U; -world::ItemInfoBuilder& world::ItemInfoBuilder::set_texture(std::string_view texture) -{ - prototype.texture = texture; - prototype.cached_texture = nullptr; - return *this; + for(const auto& item : world::item_registry::items) { + registry_checksum = item->get_checksum(registry_checksum); + } } -world::ItemInfoBuilder& world::ItemInfoBuilder::set_place_voxel(const Voxel* place_voxel) +world::Item* world::item_registry::register_item(const ItemBuilder& builder) { - prototype.place_voxel = place_voxel; - return *this; -} + assert(builder.get_name().size()); + assert(nullptr == find(builder.get_name())); -item_id world::ItemInfoBuilder::build(void) const -{ - const auto it = world::item_registry::names.find(prototype.name); + const auto id = static_cast(1 + items.size()); - if(it != world::item_registry::names.cend()) { - spdlog::warn("item_registry: cannot build {}: name already present", prototype.name); - return it->second; - } + std::unique_ptr item(builder.build(id)); + names.emplace(std::string(builder.get_name()), id); + items.push_back(std::move(item)); - auto new_info = std::make_shared(); - new_info->name = prototype.name; - new_info->texture = prototype.texture; - new_info->place_voxel = prototype.place_voxel; - new_info->cached_texture = nullptr; + recalculate_checksum(); - world::item_registry::items.push_back(new_info); - world::item_registry::names.insert_or_assign(prototype.name, static_cast(world::item_registry::items.size())); - - return static_cast(world::item_registry::items.size()); + return items.back().get(); } -world::ItemInfoBuilder& world::item_registry::construct(std::string_view name) +world::Item* world::item_registry::find(std::string_view name) { - const auto it = world::item_registry::builders.find(std::string(name)); - - if(it != world::item_registry::builders.cend()) { - return it->second; - } - else { - return world::item_registry::builders.emplace(std::string(name), ItemInfoBuilder(name)).first->second; - } -} + const auto it = names.find(std::string(name)); -world::ItemInfo* world::item_registry::find(std::string_view name) -{ - const auto it = world::item_registry::names.find(std::string(name)); - - if(it != world::item_registry::names.cend()) { - return world::item_registry::find(it->second); - } - else { + if(it == names.end()) { return nullptr; } + + return items[it->second - 1].get(); } -world::ItemInfo* world::item_registry::find(const item_id item) +world::Item* world::item_registry::find(const item_id item) { - if((item != NULL_ITEM_ID) && (item <= world::item_registry::items.size())) { - return world::item_registry::items[item - 1].get(); - } - else { + if(item == NULL_ITEM_ID || item > items.size()) { return nullptr; } + + return items[item - 1].get(); } void world::item_registry::purge(void) { - world::item_registry::builders.clear(); - world::item_registry::names.clear(); - world::item_registry::items.clear(); + registry_checksum = 0U; + items.clear(); + names.clear(); } -std::uint64_t world::item_registry::calculate_checksum(void) +std::uint64_t world::item_registry::get_checksum(void) { - std::uint64_t result = 0; - - for(const auto& info : world::item_registry::items) { - result = math::crc64(info->name, result); - - if(info->place_voxel) { - result += static_cast(info->place_voxel->get_id()); - } - } - - return result; + return registry_checksum; } diff --git a/game/shared/world/item_registry.hh b/game/shared/world/item_registry.hh index 2274da2..b4c9fda 100644 --- a/game/shared/world/item_registry.hh +++ b/game/shared/world/item_registry.hh @@ -1,61 +1,18 @@ #pragma once -#include "core/resource/resource.hh" - -#include "shared/types.hh" - -// This resource is only defined client-side and -// resource_ptr should remain set to null -// anywhere else in the shared and server code -struct TextureGUI; - -namespace world -{ -class Voxel; -} // namespace world - -namespace world -{ -struct ItemInfo final { - std::string name; - std::string texture; - const Voxel* place_voxel; - - resource_ptr cached_texture; // Client-side only -}; -} // namespace world - -namespace world -{ -class ItemInfoBuilder final { -public: - explicit ItemInfoBuilder(std::string_view name); - virtual ~ItemInfoBuilder(void) = default; - -public: - ItemInfoBuilder& set_texture(std::string_view texture); - ItemInfoBuilder& set_place_voxel(const Voxel* place_voxel); - -public: - item_id build(void) const; - -private: - ItemInfo prototype; -}; -} // namespace world +#include "shared/world/item.hh" namespace world::item_registry { -extern std::unordered_map builders; extern std::unordered_map names; -extern std::vector> items; +extern std::vector> items; } // namespace world::item_registry namespace world::item_registry { -ItemInfoBuilder& construct(std::string_view name); -ItemInfo* find(std::string_view name); -ItemInfo* find(const item_id item); +Item* register_item(const ItemBuilder& builder); +Item* find(std::string_view name); +Item* find(const item_id item); } // namespace world::item_registry namespace world::item_registry @@ -65,5 +22,5 @@ void purge(void); namespace world::item_registry { -std::uint64_t calculate_checksum(void); +std::uint64_t get_checksum(void); } // namespace world::item_registry diff --git a/game/shared/world/voxel.cc b/game/shared/world/voxel.cc index 1cd1504..21fe62c 100644 --- a/game/shared/world/voxel.cc +++ b/game/shared/world/voxel.cc @@ -55,7 +55,7 @@ void world::Voxel::set_face_cache(VoxelFace face, std::size_t offset, std::size_ m_cached_face_planes[face] = plane; } -std::uint64_t world::Voxel::calculate_checksum(std::uint64_t combine) const +std::uint64_t world::Voxel::get_checksum(std::uint64_t combine) const { combine = math::crc64(m_name.data(), m_name.size(), combine); combine += static_cast(m_shape); @@ -68,102 +68,76 @@ world::VoxelBuilder::VoxelBuilder(std::string_view name) set_name(name); } -world::VoxelBuilder& world::VoxelBuilder::set_on_place(VoxelOnPlaceFunc func) noexcept +void 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 +void 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 +void world::VoxelBuilder::set_on_tick(VoxelOnTickFunc func) noexcept { m_on_tick = std::move(func); - - return *this; } -world::VoxelBuilder& world::VoxelBuilder::set_name(std::string_view name) noexcept +void world::VoxelBuilder::set_name(std::string_view name) noexcept { assert(name.size()); m_name = name; - - return *this; } -world::VoxelBuilder& world::VoxelBuilder::set_render_mode(VoxelRender mode) noexcept +void world::VoxelBuilder::set_render_mode(VoxelRender mode) noexcept { m_render_mode = mode; - - return *this; } -world::VoxelBuilder& world::VoxelBuilder::set_shape(VoxelShape shape) noexcept +void world::VoxelBuilder::set_shape(VoxelShape shape) noexcept { m_shape = shape; - - return *this; } -world::VoxelBuilder& world::VoxelBuilder::set_animated(bool animated) noexcept +void world::VoxelBuilder::set_animated(bool animated) noexcept { m_animated = animated; - - return *this; } -world::VoxelBuilder& world::VoxelBuilder::set_touch_type(VoxelTouch type) noexcept +void world::VoxelBuilder::set_touch_type(VoxelTouch type) noexcept { m_touch_type = type; - - return *this; } -world::VoxelBuilder& world::VoxelBuilder::set_touch_values(const glm::fvec3& values) noexcept +void world::VoxelBuilder::set_touch_values(const glm::fvec3& values) noexcept { m_touch_values = values; - - return *this; } -world::VoxelBuilder& world::VoxelBuilder::set_surface_material(VoxelMaterial material) noexcept +void world::VoxelBuilder::set_surface_material(VoxelMaterial material) noexcept { m_surface_material = material; - - return *this; } -world::VoxelBuilder& world::VoxelBuilder::set_collision(const math::AABBf& box) noexcept +void world::VoxelBuilder::set_collision(const math::AABBf& box) noexcept { m_collision = box; - - return *this; } -world::VoxelBuilder& world::VoxelBuilder::add_default_texture(std::string_view path) +void world::VoxelBuilder::add_default_texture(std::string_view path) { assert(path.size()); m_default_textures.emplace_back(path); - - return *this; } -world::VoxelBuilder& world::VoxelBuilder::add_face_texture(VoxelFace face, std::string_view path) +void 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::VoxelBuilder::build(voxel_id id) const diff --git a/game/shared/world/voxel.hh b/game/shared/world/voxel.hh index 9cc0e4c..6013962 100644 --- a/game/shared/world/voxel.hh +++ b/game/shared/world/voxel.hh @@ -129,7 +129,7 @@ public: /// Calculate a checksum for the voxel's properties /// @param combine An optional initial checksum to combine with /// @return The calculated checksum - std::uint64_t calculate_checksum(std::uint64_t combine = 0U) const; + std::uint64_t get_checksum(std::uint64_t combine = 0U) const; protected: std::string m_name; @@ -163,24 +163,24 @@ 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; + void set_on_place(VoxelOnPlaceFunc func) noexcept; + void set_on_remove(VoxelOnRemoveFunc func) noexcept; + void set_on_tick(VoxelOnTickFunc func) noexcept; - VoxelBuilder& set_name(std::string_view name) noexcept; + void 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; + void set_render_mode(VoxelRender mode) noexcept; + void set_shape(VoxelShape shape) noexcept; + void 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; + void set_touch_type(VoxelTouch type) noexcept; + void set_touch_values(const glm::fvec3& values) noexcept; + void set_surface_material(VoxelMaterial material) noexcept; - VoxelBuilder& set_collision(const math::AABBf& box) noexcept; + void 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); + void add_default_texture(std::string_view path); + void add_face_texture(VoxelFace face, std::string_view path); std::unique_ptr build(voxel_id id) const; }; diff --git a/game/shared/world/voxel_registry.cc b/game/shared/world/voxel_registry.cc index 97485e6..573a606 100644 --- a/game/shared/world/voxel_registry.cc +++ b/game/shared/world/voxel_registry.cc @@ -11,7 +11,7 @@ static void recalculate_checksum(void) registry_checksum = 0U; for(const auto& voxel : world::voxel_registry::voxels) { - registry_checksum = voxel->calculate_checksum(registry_checksum); + registry_checksum = voxel->get_checksum(registry_checksum); } } @@ -39,7 +39,7 @@ world::Voxel* world::voxel_registry::find(std::string_view name) return nullptr; } - return voxels[it->second].get(); + return voxels[it->second - 1].get(); } world::Voxel* world::voxel_registry::find(voxel_id id) -- cgit