aboutsummaryrefslogtreecommitdiff
path: root/src/shared/item
diff options
context:
space:
mode:
authorNicolas James <Eele1Ephe7uZahRie@tutanota.com>2025-02-12 21:57:46 +1100
committerNicolas James <Eele1Ephe7uZahRie@tutanota.com>2025-02-12 21:57:46 +1100
commite4483eca01b48b943cd0461e24a74ae1a3139ed4 (patch)
treeed58c3c246e3af1af337697695d780aa31f6ad9a /src/shared/item
parent1cc08c51eb4b0f95c30c0a98ad1fc5ad3459b2df (diff)
Update to most recent version (old initial commit)
Diffstat (limited to 'src/shared/item')
-rw-r--r--src/shared/item/block.cc16
-rw-r--r--src/shared/item/block.hh41
-rw-r--r--src/shared/item/item.cc14
-rw-r--r--src/shared/item/item.hh49
-rw-r--r--src/shared/item/items.cc164
-rw-r--r--src/shared/item/items.hh54
6 files changed, 338 insertions, 0 deletions
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<std::uint32_t>(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<std::uint8_t>::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 <typename... Args>
+ block(const enum shared::world::block::type& type, Args&&... args) noexcept
+ : item(get_type(type), std::forward<Args>(args)...), type(type) {}
+
+ template <typename... Args>
+ block(const shared::item::item::type_t& type, Args&&... args) noexcept
+ : item(type, std::forward<Args>(args)...),
+ type(static_cast<enum shared::world::block::type>(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 <cstdint>
+
+#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<block>(type, quantity);
+ }
+ // TODO others
+ return std::make_shared<block>(type, quantity);
+}
+
+item_t make_item(const enum shared::world::block::type& type,
+ const std::uint32_t& quantity) noexcept {
+ return std::make_shared<block>(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<enum shared::world::block::type>(type - offset);
+ return make_item(block, item.quantity());
+ }
+ return make_item(static_cast<item::type_t>(item.type()), item.quantity());
+}
+
+items::items(const proto::item_array& proto) noexcept {
+ const auto length = static_cast<unsigned long>(proto.items_size());
+ for (auto i = 0ul; i < length; ++i) {
+
+ const auto& item = proto.items().at(static_cast<int>(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<std::uint32_t>(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 <memory>
+
+#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<item>;
+using items_t = std::array<item_t, 50>;
+
+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