feat: add enchantCode and validEnchantKind

This commit is contained in:
dualfroz committed 2026-09-07 19:45:19 +02:00
1 parent 7ca8ae21c3
commit 0bb301ea22
1 file changed
+160
+160
View File
@@ -0,0 +1,160 @@
#include "vf/ItemStack.h"
#include <algorithm>
namespace vf {
namespace {
int16_t enchantCode(EnchantKind kind) { return static_cast<int16_t>(kind); }
bool validEnchantKind(int32_t raw) {
return raw >= 0 && raw < static_cast<int32_t>(EnchantKind::Count);
}
bool validItemId(int32_t raw) { return raw > 0 && raw < static_cast<int32_t>(ItemId::Count); }
const NbtTag* findTyped(const NbtTag& compound, const std::string& key, NbtType type) {
const NbtTag* found = compound.find(key);
if (found == nullptr || found->kind() != type) return nullptr;
return found;
}
int32_t intField(const NbtTag& compound, const std::string& key, NbtType type, int32_t fallback) {
const NbtTag* found = findTyped(compound, key, type);
return found == nullptr ? fallback : found->asInt();
}
} // namespace
float Durability::fraction() const {
if (max <= 0) return 1.0f;
int left = remaining();
return static_cast<float>(left) / static_cast<float>(max);
}
bool sameEnchants(const EnchantSet& a, const EnchantSet& b) {
if (a.entries.size() != b.entries.size()) return false;
for (const Enchantment& entry : a.entries) {
if (b.levelOf(entry.kind) != entry.level) return false;
}
return true;
}
bool StackMeta::pristine() const {
return durability.used == 0 && enchants.empty() && customName.empty() && !unbreakable &&
repairCost == 0;
}
bool StackMeta::operator==(const StackMeta& other) const {
return durability == other.durability && unbreakable == other.unbreakable &&
repairCost == other.repairCost && customName == other.customName &&
sameEnchants(enchants, other.enchants);
}
int stackLimitFor(ItemId item) {
if (item == ItemId::None) return 0;
return maxStackSize(item);
}
int MetaStack::maxCount() const {
if (item == ItemId::None) return 0;
if (meta.durability.damageable() || !meta.enchants.empty() || meta.unbreakable ||
!meta.customName.empty()) {
return 1;
}
return stackLimitFor(item);
}
int MetaStack::room() const {
if (item == ItemId::None) return 0;
int left = maxCount() - count;
return left > 0 ? left : 0;
}
void MetaStack::clear() {
item = ItemId::None;
count = 0;
meta = StackMeta{};
}
MetaStack makeStack(ItemId item, int count) {
MetaStack stack;
if (item == ItemId::None || count <= 0) return stack;
stack.item = item;
stack.count = count;
if (isTool(item)) stack.meta.durability = {0, toolMaxDurability(item)};
int cap = stack.maxCount();
if (stack.count > cap) stack.count = cap;
return stack;
}
MetaStack makeTool(ItemId toolItem) {
MetaStack stack;
if (!isTool(toolItem)) return stack;
stack.item = toolItem;
stack.count = 1;
stack.meta.durability = {0, toolMaxDurability(toolItem)};
return stack;
}
MetaStack makeNamedStack(ItemId item, int count, const std::string& name) {
MetaStack stack = makeStack(item, count);
if (stack.empty()) return stack;
stack.meta.customName = name;
int cap = stack.maxCount();
if (stack.count > cap) stack.count = cap;
return stack;
}
MetaStack makeEnchantedTool(ItemId toolItem, const EnchantSet& enchants) {
MetaStack stack = makeTool(toolItem);
if (stack.empty()) return stack;
stack.meta.enchants = enchants;
return stack;
}
bool stacksMergeable(const MetaStack& a, const MetaStack& b) {
if (a.empty() || b.empty()) return false;
if (a.item != b.item) return false;
return a.meta == b.meta;
}
bool stacksIdentical(const MetaStack& a, const MetaStack& b) {
if (a.empty() && b.empty()) return true;
return stacksMergeable(a, b) && a.count == b.count;
}
StackTransfer transferStack(MetaStack& from, MetaStack& into, int amount) {
StackTransfer transfer;
if (from.empty() || amount <= 0) {
transfer.sourceEmptied = from.empty();
return transfer;
}
if (into.empty()) {
into.item = from.item;
into.meta = from.meta;
into.count = 0;
} else if (!stacksMergeable(from, into)) {
transfer.incompatible = true;
return transfer;
}
int movable = std::min({amount, from.count, into.room()});
if (movable <= 0) {
transfer.destinationFull = true;
return transfer;
}
into.count += movable;
from.count -= movable;
transfer.moved = movable;
if (from.count <= 0) {
from.clear();
transfer.sourceEmptied = true;
}
transfer.destinationFull = into.full();
return transfer;
}