#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