From b691c43c44ff180d10e7d4a9afc83b98551ff586 Mon Sep 17 00:00:00 2001 From: daoge_cmd <3523206925@qq.com> Date: Sun, 1 Mar 2026 12:16:08 +0800 Subject: Initial commit --- Minecraft.World/ItemInstance.cpp | 727 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 727 insertions(+) create mode 100644 Minecraft.World/ItemInstance.cpp (limited to 'Minecraft.World/ItemInstance.cpp') diff --git a/Minecraft.World/ItemInstance.cpp b/Minecraft.World/ItemInstance.cpp new file mode 100644 index 00000000..ab042af0 --- /dev/null +++ b/Minecraft.World/ItemInstance.cpp @@ -0,0 +1,727 @@ +#include "stdafx.h" +#include "com.mojang.nbt.h" +#include "net.minecraft.locale.h" +#include "net.minecraft.stats.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.item.enchantment.h" +#include "Item.h" +#include "ItemInstance.h" + + + +const wchar_t *ItemInstance::TAG_ENCH_ID = L"id"; +const wchar_t *ItemInstance::TAG_ENCH_LEVEL = L"lvl"; + +void ItemInstance::_init(int id, int count, int auxValue) +{ + this->popTime = 0; + this->id = id; + this->count = count; + this->auxValue = auxValue; + this->tag = NULL; + this->frame = nullptr; + // 4J-PB - for trading menu + this->m_bForceNumberDisplay=false; +} + +ItemInstance::ItemInstance(Tile *tile) +{ + _init(tile->id, 1, 0); +} + +ItemInstance::ItemInstance(Tile *tile, int count) +{ + _init(tile->id, count, 0); +} +// 4J-PB - added +ItemInstance::ItemInstance(MapItem *item, int count) +{ + _init(item->id, count, 0); +} + +ItemInstance::ItemInstance(Tile *tile, int count, int auxValue) +{ + _init(tile->id, count, auxValue); +} + +ItemInstance::ItemInstance(Item *item) +{ + _init(item->id, 1, 0); +} + + + +ItemInstance::ItemInstance(Item *item, int count) +{ + _init(item->id, count, 0); +} + +ItemInstance::ItemInstance(Item *item, int count, int auxValue) +{ + _init(item->id, count, auxValue); +} + +ItemInstance::ItemInstance(int id, int count, int damage) +{ + _init(id,count,damage); +} + +shared_ptr ItemInstance::fromTag(CompoundTag *itemTag) +{ + shared_ptr itemInstance = shared_ptr(new ItemInstance()); + itemInstance->load(itemTag); + return itemInstance->getItem() != NULL ? itemInstance : nullptr; +} + +ItemInstance::~ItemInstance() +{ + if(tag != NULL) delete tag; +} + +shared_ptr ItemInstance::remove(int count) +{ + shared_ptr ii = shared_ptr( new ItemInstance(id, count, auxValue) ); + if (tag != NULL) ii->tag = (CompoundTag *) tag->copy(); + this->count -= count; + + // 4J Stu Fix for duplication glitch, make sure that item count is in range + if(this->count <= 0) + { + this->count = 0; + } + return ii; +} + +Item *ItemInstance::getItem() const +{ + return Item::items[id]; +} + +Icon *ItemInstance::getIcon() +{ + return getItem()->getIcon(shared_from_this()); +} + +int ItemInstance::getIconType() +{ + return getItem()->getIconType(); +} + +bool ItemInstance::useOn(shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) +{ + return getItem()->useOn(shared_from_this(), player, level, x, y, z, face, clickX, clickY, clickZ, bTestUseOnOnly); +} + +float ItemInstance::getDestroySpeed(Tile *tile) +{ + return getItem()->getDestroySpeed(shared_from_this(), tile); +} + +bool ItemInstance::TestUse(Level *level, shared_ptr player) +{ + return getItem()->TestUse( level, player); +} + +shared_ptr ItemInstance::use(Level *level, shared_ptr player) +{ + return getItem()->use(shared_from_this(), level, player); +} + +shared_ptr ItemInstance::useTimeDepleted(Level *level, shared_ptr player) +{ + return getItem()->useTimeDepleted(shared_from_this(), level, player); +} + +CompoundTag *ItemInstance::save(CompoundTag *compoundTag) +{ + compoundTag->putShort(L"id", (short) id); + compoundTag->putByte(L"Count", (byte) count); + compoundTag->putShort(L"Damage", (short) auxValue); + if (this->tag != NULL) compoundTag->put(L"tag", tag->copy()); + return compoundTag; +} + +void ItemInstance::load(CompoundTag *compoundTag) +{ + popTime = 0; + id = compoundTag->getShort(L"id"); + count = compoundTag->getByte(L"Count"); + auxValue = compoundTag->getShort(L"Damage"); + if (compoundTag->contains(L"tag")) + { + tag = (CompoundTag *)compoundTag->getCompound(L"tag")->copy(); + } +} + +int ItemInstance::getMaxStackSize() +{ + return getItem()->getMaxStackSize(); +} + +bool ItemInstance::isStackable() +{ + return getMaxStackSize() > 1 && (!isDamageableItem() || !isDamaged()); +} + +bool ItemInstance::isDamageableItem() +{ + return Item::items[id]->getMaxDamage() > 0; +} + +/** + * Returns true if this item type only can be stacked with items that have + * the same auxValue data. + * + * @return + */ + +bool ItemInstance::isStackedByData() +{ + return Item::items[id]->isStackedByData(); +} + +bool ItemInstance::isDamaged() +{ + return isDamageableItem() && auxValue > 0; +} + +int ItemInstance::getDamageValue() +{ + return auxValue; +} + +int ItemInstance::getAuxValue() const +{ + return auxValue; +} + +void ItemInstance::setAuxValue(int value) +{ + auxValue = value; +} + +int ItemInstance::getMaxDamage() +{ + return Item::items[id]->getMaxDamage(); +} + +void ItemInstance::hurt(int i, shared_ptr owner) +{ + if (!isDamageableItem()) + { + return; + } + + shared_ptr player = dynamic_pointer_cast(owner); + if (i > 0 && player != NULL) + { + int enchanted = EnchantmentHelper::getDigDurability(player->inventory); + // Fix for #65233 - TU8: Content: Gameplay: Tools Enchanted with "Unbreaking" occasionally repair themselves. + // 4J Stu - If it's the clientside level, then always assume that no damage is done. This stops the case where the client random + // results in damage, but the server random does not + if (enchanted > 0 && (owner->level->isClientSide || owner->level->random->nextInt(enchanted + 1) > 0) ) + { + // enchantment prevents damage + return; + } + } + + // 4J Stu - Changed in TU6 to not damage items in creative mode + if (!(owner != NULL && player->abilities.instabuild)) auxValue += i; + + if (auxValue > getMaxDamage()) + { + owner->breakItem(shared_from_this()); + count--; + if (count < 0) count = 0; + auxValue = 0; + } +} + +void ItemInstance::hurtEnemy(shared_ptr mob, shared_ptr attacker) +{ + //bool used = + Item::items[id]->hurtEnemy(shared_from_this(), mob, attacker); +} + +void ItemInstance::mineBlock(Level *level, int tile, int x, int y, int z, shared_ptr owner) +{ + //bool used = + Item::items[id]->mineBlock( shared_from_this(), level, tile, x, y, z, owner); +} + +int ItemInstance::getAttackDamage(shared_ptr entity) +{ + return Item::items[id]->getAttackDamage(entity); +} + +bool ItemInstance::canDestroySpecial(Tile *tile) +{ + return Item::items[id]->canDestroySpecial(tile); +} + +bool ItemInstance::interactEnemy(shared_ptr mob) +{ + return Item::items[id]->interactEnemy(shared_from_this(), mob); +} + +shared_ptr ItemInstance::copy() const +{ + shared_ptr copy = shared_ptr( new ItemInstance(id, count, auxValue) ); + if (tag != NULL) + { + copy->tag = (CompoundTag *) tag->copy(); + } + return copy; +} + +// 4J Stu - Added this as we need it in the recipe code +ItemInstance *ItemInstance::copy_not_shared() const +{ + ItemInstance *copy = new ItemInstance(id, count, auxValue); + if (tag != NULL) + { + copy->tag = (CompoundTag *) tag->copy(); + if (!copy->tag->equals(tag)) + { + return copy; + } + } + return copy; +} + +// 4J Brought forward from 1.2 +bool ItemInstance::tagMatches(shared_ptr a, shared_ptr b) +{ + if (a == NULL && b == NULL) return true; + if (a == NULL || b == NULL) return false; + + if (a->tag == NULL && b->tag != NULL) + { + return false; + } + if (a->tag != NULL && !a->tag->equals(b->tag)) + { + return false; + } + return true; +} + +bool ItemInstance::matches(shared_ptr a, shared_ptr b) +{ + if (a == NULL && b == NULL) return true; + if (a == NULL || b == NULL) return false; + return a->matches(b); +} + +bool ItemInstance::matches(shared_ptr b) +{ + if (count != b->count) return false; + if (id != b->id) return false; + if (auxValue != b->auxValue) return false; + if (tag == NULL && b->tag != NULL) + { + return false; + } + if (tag != NULL && !tag->equals(b->tag)) + { + return false; + } + return true; +} + +/** + * Checks if this item is the same item as the other one, disregarding the + * 'count' value. + * + * @param b + * @return + */ +bool ItemInstance::sameItem(shared_ptr b) +{ + return id == b->id && auxValue == b->auxValue; +} + +bool ItemInstance::sameItemWithTags(shared_ptr b) +{ + if (id != b->id) return false; + if (auxValue != b->auxValue) return false; + if (tag == NULL && b->tag != NULL) + { + return false; + } + if (tag != NULL && !tag->equals(b->tag)) + { + return false; + } + return true; +} + +// 4J Stu - Added this for the one time when we compare with a non-shared pointer +bool ItemInstance::sameItem_not_shared(ItemInstance *b) +{ + return id == b->id && auxValue == b->auxValue; +} + +unsigned int ItemInstance::getUseDescriptionId() +{ + return Item::items[id]->getUseDescriptionId(shared_from_this()); +} + +unsigned int ItemInstance::getDescriptionId(int iData /*= -1*/) +{ + return Item::items[id]->getDescriptionId(shared_from_this()); +} + +ItemInstance *ItemInstance::setDescriptionId(unsigned int id) +{ + // 4J Stu - I don't think this function is ever used. It if is, it should probably return shared_from_this() + assert(false); + return this; +} + +shared_ptr ItemInstance::clone(shared_ptr item) +{ + return item == NULL ? nullptr : item->copy(); +} + +wstring ItemInstance::toString() +{ + //return count + "x" + Item::items[id]->getDescriptionId() + "@" + auxValue; + + std::wostringstream oss; + // 4J-PB - TODO - temp fix until ore recipe issue is fixed + if(Item::items[id]==NULL) + { + oss << std::dec << count << L"x" << L" Item::items[id] is NULL " << L"@" << auxValue; + } + else + { + oss << std::dec << count << L"x" << Item::items[id]->getDescription(shared_from_this()) << L"@" << auxValue; + } + return oss.str(); +} + +void ItemInstance::inventoryTick(Level *level, shared_ptr owner, int slot, bool selected) +{ + if (popTime > 0) popTime--; + Item::items[id]->inventoryTick(shared_from_this(), level, owner, slot, selected); +} + +void ItemInstance::onCraftedBy(Level *level, shared_ptr player, int craftCount) +{ + // 4J Stu Added for tutorial callback + player->onCrafted(shared_from_this()); + + player->awardStat( + GenericStats::itemsCrafted(id), + GenericStats::param_itemsCrafted(id, auxValue, craftCount) + ); + + Item::items[id]->onCraftedBy(shared_from_this(), level, player); +} + +bool ItemInstance::equals(shared_ptr ii) +{ + return id == ii->id && count == ii->count && auxValue == ii->auxValue; +} + +int ItemInstance::getUseDuration() +{ + return getItem()->getUseDuration(shared_from_this()); +} + +UseAnim ItemInstance::getUseAnimation() +{ + return getItem()->getUseAnimation(shared_from_this()); +} + +void ItemInstance::releaseUsing(Level *level, shared_ptr player, int durationLeft) +{ + getItem()->releaseUsing(shared_from_this(), level, player, durationLeft); +} + +// 4J Stu - Brought forward these functions for enchanting/game rules +bool ItemInstance::hasTag() +{ + return tag != NULL; +} + +CompoundTag *ItemInstance::getTag() +{ + return tag; +} + +ListTag *ItemInstance::getEnchantmentTags() +{ + if (tag == NULL) + { + return NULL; + } + return (ListTag *) tag->get(L"ench"); +} + +void ItemInstance::setTag(CompoundTag *tag) +{ + this->tag = tag; +} + +wstring ItemInstance::getHoverName() +{ + wstring title = getItem()->getHoverName(shared_from_this()); + + if (tag != NULL && tag->contains(L"display")) + { + CompoundTag *display = tag->getCompound(L"display"); + + if (display->contains(L"Name")) + { + title = display->getString(L"Name"); + } + } + + return title; +} + +void ItemInstance::setHoverName(const wstring &name) +{ + if (tag == NULL) tag = new CompoundTag(); + if (!tag->contains(L"display")) tag->putCompound(L"display", new CompoundTag()); + tag->getCompound(L"display")->putString(L"Name", name); +} + +bool ItemInstance::hasCustomHoverName() +{ + if (tag == NULL) return false; + if (!tag->contains(L"display")) return false; + return tag->getCompound(L"display")->contains(L"Name"); +} + +vector *ItemInstance::getHoverText(shared_ptr player, bool advanced, vector &unformattedStrings) +{ + vector *lines = new vector(); + Item *item = Item::items[id]; + wstring title = getHoverName(); + + // 4J Stu - We don't do italics, but do change colour. But handle this later in the process due to text length measuring on the Xbox360 + //if (hasCustomHoverName()) + //{ + // title = L"" + title + L""; + //} + + // 4J Stu - Don't currently have this + //if (advanced) + //{ + // String suffix = ""; + + // if (title.length() > 0) { + // title += " ("; + // suffix = ")"; + // } + + // if (isStackedByData()) + // { + // title += String.format("#%04d/%d%s", id, auxValue, suffix); + // } + // else + // { + // title += String.format("#%04d%s", id, suffix); + // } + //} + //else + // if (!hasCustomHoverName()) + //{ + // if (id == Item::map_Id) + // { + // title += L" #" + _toString(auxValue); + // } + //} + + lines->push_back(title); + unformattedStrings.push_back(title); + item->appendHoverText(shared_from_this(), player, lines, advanced, unformattedStrings); + + if (hasTag()) + { + ListTag *list = getEnchantmentTags(); + if (list != NULL) + { + for (int i = 0; i < list->size(); i++) + { + int type = list->get(i)->getShort((wchar_t *)TAG_ENCH_ID); + int level = list->get(i)->getShort((wchar_t *)TAG_ENCH_LEVEL); + + if (Enchantment::enchantments[type] != NULL) + { + wstring unformatted = L""; + lines->push_back(Enchantment::enchantments[type]->getFullname(level, unformatted)); + unformattedStrings.push_back(unformatted); + } + } + } + } + return lines; +} + +// 4J Added +vector *ItemInstance::getHoverTextOnly(shared_ptr player, bool advanced, vector &unformattedStrings) +{ + vector *lines = new vector(); + Item *item = Item::items[id]; + + item->appendHoverText(shared_from_this(), player, lines, advanced, unformattedStrings); + + if (hasTag()) + { + ListTag *list = getEnchantmentTags(); + if (list != NULL) + { + for (int i = 0; i < list->size(); i++) + { + int type = list->get(i)->getShort((wchar_t *)TAG_ENCH_ID); + int level = list->get(i)->getShort((wchar_t *)TAG_ENCH_LEVEL); + + if (Enchantment::enchantments[type] != NULL) + { + wstring unformatted = L""; + lines->push_back(Enchantment::enchantments[type]->getFullname(level,unformatted)); + unformattedStrings.push_back(unformatted); + } + } + } + } + return lines; +} + +bool ItemInstance::isFoil() +{ + return getItem()->isFoil(shared_from_this()); +} + +const Rarity *ItemInstance::getRarity() +{ + return getItem()->getRarity(shared_from_this()); +} + +bool ItemInstance::isEnchantable() +{ + if (!getItem()->isEnchantable(shared_from_this())) return false; + if (isEnchanted()) return false; + return true; +} + +void ItemInstance::enchant(const Enchantment *enchantment, int level) +{ + if (tag == NULL) this->setTag(new CompoundTag()); + if (!tag->contains(L"ench")) tag->put(L"ench", new ListTag(L"ench")); + + ListTag *list = (ListTag *) tag->get(L"ench"); + CompoundTag *ench = new CompoundTag(); + ench->putShort((wchar_t *)TAG_ENCH_ID, (short) enchantment->id); + ench->putShort((wchar_t *)TAG_ENCH_LEVEL, (byte) level); + list->add(ench); +} + +bool ItemInstance::isEnchanted() +{ + if (tag != NULL && tag->contains(L"ench")) return true; + return false; +} + +void ItemInstance::addTagElement(wstring name, Tag *tag) +{ + if (this->tag == NULL) + { + this->setTag(new CompoundTag()); + } + this->tag->put((wchar_t *)name.c_str(), tag); +} + +void ItemInstance::set4JData(int data) +{ + if(tag == NULL && data == 0) return; + if (tag == NULL) this->setTag(new CompoundTag()); + + if (tag->contains(L"4jdata")) + { + IntTag *dataTag = (IntTag *)tag->get(L"4jdata"); + dataTag->data = data; + } + else if(data != 0) + { + tag->put(L"4jdata", new IntTag(L"4jdata",data)); + } +} + +int ItemInstance::get4JData() +{ + if(tag == NULL || !tag->contains(L"4jdata")) return 0; + else + { + IntTag *dataTag = (IntTag *)tag->get(L"4jdata"); + return dataTag->data; + } +} +// 4J Added - to show strength on potions +bool ItemInstance::hasPotionStrengthBar() +{ + // exclude a bottle of water from this + if((id==Item::potion_Id) && (auxValue !=0))// && (!MACRO_POTION_IS_AKWARD(auxValue))) 4J-PB leaving the bar on an awkward potion so we can differentiate it from a water bottle + { + return true; + } + + return false; +} + +int ItemInstance::GetPotionStrength() +{ + if(MACRO_POTION_IS_INSTANTDAMAGE(auxValue) || MACRO_POTION_IS_INSTANTHEALTH(auxValue) ) + { + // The two instant potions don't have extended versions + return (auxValue&MASK_LEVEL2)>>5; + } + else + { + return (auxValue&MASK_LEVEL2EXTENDED)>>5; + } +} + +// TU9 + +bool ItemInstance::isFramed() +{ + return frame != NULL; +} + +void ItemInstance::setFramed(shared_ptr frame) +{ + this->frame = frame; +} + +shared_ptr ItemInstance::getFrame() +{ + return frame; +} + +int ItemInstance::getBaseRepairCost() +{ + if (hasTag() && tag->contains(L"RepairCost")) + { + return tag->getInt(L"RepairCost"); + } + else + { + return 0; + } +} + +void ItemInstance::setRepairCost(int cost) +{ + if (!hasTag()) tag = new CompoundTag(); + tag->putInt(L"RepairCost", cost); +} -- cgit v1.2.3