#pragma once #include #include "flecs.h" #include "Types/Item.hpp" #include "Util/SharedBuffer.h" #include "Util/Span.h" template struct InventoryT { struct InventoryMeta { IntegralType MaxSize{ std::numeric_limits::max() }; }; public: InventoryT() = default; InventoryT(size_t itemAmount) { Slots = { static_cast(itemAmount), InventoryMeta{} }; } InventoryT(size_t itemAmount, IntegralType maxAmount) { Slots = { static_cast(itemAmount), InventoryMeta{ maxAmount } }; } public: IntegralType GetItemsAmount(uint16_t id) const { Assert(id); return Slots[id]; } IntegralType GetItemsAmount(Item item) const { return GetItemsAmount(item.ItemID); } void RemoveItems(uint16_t id, IntegralType amount) { Assert(id); Slots[id]-= amount; } void RemoveItems(Item id, IntegralType amount) { RemoveItems(id.ItemID, amount); } template void RemoveItems(ItemAmountT amount) { RemoveItems(amount.Item, amount.Amount); } void AddItems(uint16_t id, IntegralType amount) { Assert(id); Slots[id]+= amount; } void AddItems(Item id, IntegralType amount) { AddItems(id.ItemID, amount); } template void AddItems(ItemAmountT item) { AddItems(item.Item.ItemID, item.Amount); } template void AddItems(const InventoryT other) { DEV_ASSERT(Slots.GetSize() == other.Slots.GetSize()); for (uint32_t i{}; i < Slots.GetSize(); ++i) Slots[i] += other.Slots[i]; } bool IsFull(uint16_t id) const { Assert(id); return Slots[id] >= Slots.GetMetaData()->MaxSize; } void Clear() { for (IntegralType i{}; i < Slots.GetSize(); ++i) Slots[i] = 0; } void Assert(uint16_t id) const { DEV_ASSERT(id < Slots.GetSize() && id != Item::null); } public: operator bool() const { return Slots; } public: SharedBuffer Slots; }; typedef InventoryT Inventory16; typedef InventoryT Inventory32; typedef InventoryT Inventory64; typedef Inventory32 Inventory; typedef Inventory64 WorldInventory; struct FixedInventoryEntry { FixedInventoryEntry() = default; FixedInventoryEntry(Item item, uint16_t amount, uint16_t maxAmount) : ItemInfo{ item }, Amount{ amount }, MaxAmount{ maxAmount } {}; Item ItemInfo{}; uint16_t Amount{}; uint16_t MaxAmount{std::numeric_limits::max()}; }; template struct FixedInventoryBase { FixedInventoryBase() = default; template FixedInventoryBase(const It& it) { int counter{}; for (const auto& val : it) Data[counter++] = val; } tcb::span GetInventoryData() { return {&Data[0], InventorySize}; } tcb::span GetInventoryData() const { return {&Data[0], InventorySize}; } uint8_t InventorySize{ Size }; std::array Data{}; }; typedef FixedInventoryBase<1> FixedInventory1; typedef FixedInventoryBase<2> FixedInventory2; typedef FixedInventoryBase<3> FixedInventory3; typedef FixedInventoryBase<4> FixedInventory4; typedef FixedInventoryBase<5> FixedInventory5; typedef FixedInventoryBase<6> FixedInventory6; typedef FixedInventoryBase<7> FixedInventory7; typedef FixedInventoryBase<8> FixedInventory8; struct InventoryAreaOfEffect { InventoryAreaOfEffect(bool isCircle, uint8_t size) : IsCircle{ isCircle } , ShapeSize{ size } { } uint8_t IsCircle : 1; uint8_t ShapeSize : 7; }; static_assert(sizeof(InventoryAreaOfEffect) == 1); struct InventoryOwner {}; struct ItemProcessor { ItemProcessor() = default; ItemProcessor(uint32_t ticks) : ProcessedTicks{ ticks } {}; uint32_t ProcessedTicks; }; inline void Flecs_Inventory(flecs::world& world) { world.component() .member("Item") .member("Amount") .member("MaxAmount"); auto fixedInv1 = world.component(); fixedInv1.add(flecs::Inheritable); fixedInv1 .opaque(world.vector()) .serialize([](const flecs::serializer *s, const FixedInventory1 *data) { for (uint8_t i = 0; i < data->InventorySize; ++i) s->value(data->Data[i]); return 0; }) .count([](const FixedInventory1 *data) -> size_t { return data->InventorySize; }) .ensure_element([](FixedInventory1 *data, size_t elem) -> void* { return &data->Data[elem]; }); world.component().is_a(); world.component().is_a(); world.component().is_a(); world.component().is_a(); world.component().is_a(); world.component().is_a(); world.component().is_a(); auto inv = world.component(); inv.add(flecs::Inheritable); inv .opaque(world.vector()) .serialize([](const flecs::serializer *s, const Inventory *data) { if (!data->Slots) return 0; for (uint32_t i = 0; i < data->Slots.GetSize(); ++i) s->value(data->Slots[i]); return 0; }) .count([](const Inventory *data) -> size_t { if (!data->Slots) return 0; return data->Slots.GetSize(); }); auto worldInv = world.component(); worldInv.add(flecs::Singleton); worldInv .opaque(world.vector()) .serialize([](const flecs::serializer *s, const WorldInventory *data) { if (!data->Slots) return 0; for (uint64_t i = 0; i < data->Slots.GetSize(); ++i) s->value(data->Slots[i]); return 0; }) .count([](const WorldInventory *data) -> size_t { if (!data->Slots) return 0; return data->Slots.GetSize(); }); world.component() .opaque(world.component() .member("IsCircle") .member("Size")) .serialize([](const flecs::serializer *s, const InventoryAreaOfEffect *data) { uint8_t isCircle = data->IsCircle; uint8_t size = data->ShapeSize; s->member("IsCircle"); s->value(isCircle); s->member("Size"); s->value(size); return 0; }); world.component() .member("ProcessedTicks"); world.component(); } inline void Inventory_Helper(const flecs::entity& entity, const WorldConfig& config, uint32_t maxPerSlot) { entity.set(Inventory{config.GetItems().size(), maxPerSlot}); entity.add(); }