From e4483eca01b48b943cd0461e24a74ae1a3139ed4 Mon Sep 17 00:00:00 2001 From: Nicolas James Date: Wed, 12 Feb 2025 21:57:46 +1100 Subject: Update to most recent version (old initial commit) --- src/shared/item/block.cc | 16 +++++ src/shared/item/block.hh | 41 ++++++++++++ src/shared/item/item.cc | 14 ++++ src/shared/item/item.hh | 49 ++++++++++++++ src/shared/item/items.cc | 164 +++++++++++++++++++++++++++++++++++++++++++++++ src/shared/item/items.hh | 54 ++++++++++++++++ 6 files changed, 338 insertions(+) create mode 100644 src/shared/item/block.cc create mode 100644 src/shared/item/block.hh create mode 100644 src/shared/item/item.cc create mode 100644 src/shared/item/item.hh create mode 100644 src/shared/item/items.cc create mode 100644 src/shared/item/items.hh (limited to 'src/shared/item') diff --git a/src/shared/item/block.cc b/src/shared/item/block.cc new file mode 100644 index 0000000..e85bea9 --- /dev/null +++ b/src/shared/item/block.cc @@ -0,0 +1,16 @@ +#include "shared/item/block.hh" + +namespace shared { +namespace item { + +item::type_t +block::get_type(const enum shared::world::block::type& type) noexcept { + return static_cast(type) + type_offset; +} + +item::type_t block::get_type() const noexcept { + return this->get_type(this->type); +} + +} // namespace item +} // namespace shared diff --git a/src/shared/item/block.hh b/src/shared/item/block.hh new file mode 100644 index 0000000..2aa7cef --- /dev/null +++ b/src/shared/item/block.hh @@ -0,0 +1,41 @@ +#ifndef SHARED_ITEM_BLOCK_HH_ +#define SHARED_ITEM_BLOCK_HH_ + +#include "shared/item/item.hh" +#include "shared/world/block.hh" + +namespace shared { +namespace item { + +class block : virtual public shared::item::item { +public: + // Blocks are offset by 256 in their type so they do not collide with tools + // I'd prefer it was the other way around so TODO + static constexpr auto type_offset{std::numeric_limits::max()}; + +public: + enum shared::world::block::type type; + +public: + static type_t get_type(const enum shared::world::block::type&) noexcept; + +public: + virtual type_t get_type() const noexcept; + +public: + template + block(const enum shared::world::block::type& type, Args&&... args) noexcept + : item(get_type(type), std::forward(args)...), type(type) {} + + template + block(const shared::item::item::type_t& type, Args&&... args) noexcept + : item(type, std::forward(args)...), + type(static_cast(type - + type_offset)) {} + virtual ~block() noexcept {} +}; + +} // namespace item +} // namespace shared + +#endif diff --git a/src/shared/item/item.cc b/src/shared/item/item.cc new file mode 100644 index 0000000..f711523 --- /dev/null +++ b/src/shared/item/item.cc @@ -0,0 +1,14 @@ +#include "shared/item/item.hh" + +namespace shared { +namespace item { + +std::uint32_t item::get_max_stack(const item::type_t& type) noexcept { + switch (type) { + default: + return 64; + } +} + +} // namespace item +} // namespace shared diff --git a/src/shared/item/item.hh b/src/shared/item/item.hh new file mode 100644 index 0000000..3774189 --- /dev/null +++ b/src/shared/item/item.hh @@ -0,0 +1,49 @@ +#ifndef SHARED_ITEM_ITEM_HH_ +#define SHARED_ITEM_ITEM_HH_ + +#include + +#include "shared/net/proto.hh" +#include "shared/world/block.hh" +#include "shared/world/chunk.hh" + +namespace shared { +namespace item { + +// ABC for items that exist in a player's inventory. (TODO abc lol) +class item { +public: + using type_t = std::uint32_t; + +public: + type_t type; + std::uint32_t quantity; + +public: + item(const type_t& type, const std::uint32_t& quantity) noexcept + : type(type), quantity(quantity) {} + item(const proto::item& item) noexcept + : type(item.type()), quantity(item.quantity()) {} + virtual ~item() noexcept {} + +public: + static std::uint32_t get_max_stack(const type_t& type) noexcept; + +public: + virtual type_t get_type() const noexcept { + return this->type; + } + +public: // protobuf stuff + void pack(proto::item* const proto, + const std::uint32_t inventory_index) const noexcept { + proto->set_type(this->type); + proto->set_quantity(this->quantity); + proto->set_index(inventory_index); + } +}; + +} // namespace item +} // namespace shared + +#endif diff --git a/src/shared/item/items.cc b/src/shared/item/items.cc new file mode 100644 index 0000000..a5540fb --- /dev/null +++ b/src/shared/item/items.cc @@ -0,0 +1,164 @@ +#include "shared/item/items.hh" + +namespace shared { +namespace item { + +item_t make_item(const item::type_t& type, + const std::uint32_t& quantity) noexcept { + if (type >= block::type_offset) { + return std::make_shared(type, quantity); + } + // TODO others + return std::make_shared(type, quantity); +} + +item_t make_item(const enum shared::world::block::type& type, + const std::uint32_t& quantity) noexcept { + return std::make_shared(type, quantity); +} + +item_t make_item(const proto::item& item) noexcept { + const auto type = item.type(); + + constexpr auto offset = shared::item::block::type_offset; + if (type >= offset) { + const auto block = + static_cast(type - offset); + return make_item(block, item.quantity()); + } + return make_item(static_cast(item.type()), item.quantity()); +} + +items::items(const proto::item_array& proto) noexcept { + const auto length = static_cast(proto.items_size()); + for (auto i = 0ul; i < length; ++i) { + + const auto& item = proto.items().at(static_cast(i)); + + const auto index = item.index(); + this->contents[index] = make_item(item); + } +} + +// Annoying logic because we have to add into existing first, then start +// adding new stacks after. +bool items::maybe_add(const item::type_t& type, const std::uint32_t& quantity, + const make_item_func_t& func) noexcept { + + const auto stack_size = item::get_max_stack(type); + + std::uint32_t added = 0; + const auto get_existing = + std::ranges::find_if(this->contents, [&](const auto& item) { + if (item == nullptr) { + return false; + } + if (item->type != type) { + return false; + } + if (item->quantity >= stack_size) { + return false; + } + return true; + }); + for (auto it = get_existing; get_existing != std::end(this->contents); + it = get_existing) { + + const auto addition = + std::min(quantity - added, stack_size - (*it)->quantity); + (*it)->quantity += addition; + added += addition; + if (added != quantity) { + continue; + } + + return true; + } + + for (auto& item : this->contents) { + if (item != nullptr) { + continue; + } + + const auto addition = std::min(quantity - added, stack_size); + item = func(type, addition); + added += addition; + if (added != quantity) { + continue; + } + + return true; + } + + return false; +} + +bool items::maybe_remove(const item::type_t& type, + const std::uint32_t& quantity) noexcept { + const auto existing_it = + std::ranges::find_if(this->contents, [&type](const auto& i) { + if (i == nullptr) { + return false; + } + return type == i->get_type(); + }); + if (existing_it == std::end(this->contents)) { + return false; + } + + auto& existing = (*existing_it)->quantity; + if (existing > quantity) { + existing -= quantity; + return true; + } + + if (existing == quantity) { + (*existing_it) = nullptr; + return true; + } + + const auto diff = quantity - existing; + (*existing_it) = nullptr; + return this->maybe_remove(type, diff); +} + +void items::pack(proto::item_array* const proto) const noexcept { + const auto items = proto->mutable_items(); + for (auto i = 0ul; i < std::size(this->contents); ++i) { + const auto& item = contents[i]; + if (item == nullptr) { + continue; + } + + proto::item proto_item; + item->pack(&proto_item, static_cast(i)); + items->Add(std::move(proto_item)); + } +} + +void items::increment(const std::uint32_t& index, + const make_item_func_t& func) noexcept { + auto& item = this->contents[index]; + if (item == nullptr) { + return; + } + if (item->quantity < shared::item::item::get_max_stack(item->type)) { + ++item->quantity; + return; + } + this->maybe_add(item->type, 1, func); +} + +void items::decrement(const std::uint32_t& index) noexcept { + auto& item = this->contents[index]; + if (item == nullptr) { + return; + } + item->quantity -= 1; + if (item->quantity == 0) { + item = nullptr; + } +} + +} // namespace item +} // namespace shared diff --git a/src/shared/item/items.hh b/src/shared/item/items.hh new file mode 100644 index 0000000..ba718c5 --- /dev/null +++ b/src/shared/item/items.hh @@ -0,0 +1,54 @@ +#ifndef SHARED_ITEM_ITEMS_HH_ +#define SHARED_ITEM_ITEMS_HH_ + +#include + +#include "shared/item/block.hh" +#include "shared/item/item.hh" +#include "shared/net/proto.hh" +#include "shared/world/block.hh" + +namespace shared { +namespace item { + +// Use this function over constructor to create a derived item. + +using item_t = std::shared_ptr; +using items_t = std::array; + +using make_item_func_t = item_t (*)(const item::type_t&, const std::uint32_t&); +item_t make_item(const item::type_t& type, + const std::uint32_t& quantity) noexcept; +item_t make_item(const proto::item& item) noexcept; + +// Class for an inventory (or possibly a chest in the future, etc). +class items { +public: + items_t contents = {0}; + +public: + items() noexcept {} + items(const proto::item_array& proto) noexcept; + +public: + // Adds or removes an arbitrary amount of items to the player. + // Returns true of false based on whether the operation completed fully. + bool maybe_add(const item::type_t& type, const std::uint32_t& quantity, + const make_item_func_t& = make_item) noexcept; + bool maybe_remove(const item::type_t& type, + const std::uint32_t& quantity) noexcept; + + // Adds a single existing item, puts in new slot if necessary. + void increment(const std::uint32_t& index, + const make_item_func_t& = make_item) noexcept; + // Removes a single existing item from an index, clears if needed. + void decrement(const std::uint32_t& index) noexcept; + +public: + void pack(proto::item_array* const proto) const noexcept; +}; + +} // namespace item +} // namespace shared + +#endif -- cgit v1.2.3