From fcafd5a2e0f87fcc79e0a723241604aeca50d017 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 15 Jan 2014 22:38:03 +0000 Subject: [PATCH] Implemented custom names and lore + Added custom names and lore + Added saving and loading + Added writing and parsing of NBT --- src/Item.cpp | 32 ++++++------------- src/Item.h | 43 +++++++++++++++++++++----- src/Protocol/Protocol17x.cpp | 60 +++++++++++++++++++++++++++++++++--- src/UI/SlotArea.cpp | 7 +++++ 4 files changed, 107 insertions(+), 35 deletions(-) diff --git a/src/Item.cpp b/src/Item.cpp index a44515019..9170006b6 100644 --- a/src/Item.cpp +++ b/src/Item.cpp @@ -91,28 +91,6 @@ bool cItem::DamageItem(short a_Amount) -bool cItem::IsStackableWith(const cItem & a_OtherStack) const -{ - if (a_OtherStack.m_ItemType != m_ItemType) - { - return false; - } - if (a_OtherStack.m_ItemDamage != m_ItemDamage) - { - return false; - } - if (a_OtherStack.m_Enchantments != m_Enchantments) - { - return false; - } - - return true; -} - - - - - bool cItem::IsFullStack(void) const { return (m_ItemCount >= ItemHandler(m_ItemType)->GetMaxStackSize()); @@ -153,6 +131,14 @@ void cItem::GetJson(Json::Value & a_OutValue) const { a_OutValue["ench"] = Enchantments; } + if (!IsCustomNameEmpty()) + { + a_OutValue["Name"] = m_CustomName; + } + if (!IsLoreEmpty()) + { + a_OutValue["Lore"] = m_Lore; + } } } @@ -169,6 +155,8 @@ void cItem::FromJson(const Json::Value & a_Value) m_ItemDamage = (short)a_Value.get("Health", -1 ).asInt(); m_Enchantments.Clear(); m_Enchantments.AddFromString(a_Value.get("ench", "").asString()); + m_CustomName = a_Value.get("Name", "").asString(); + m_Lore = a_Value.get("Lore", "").asString(); } } diff --git a/src/Item.h b/src/Item.h index 64a30ade1..a59ab0348 100644 --- a/src/Item.h +++ b/src/Item.h @@ -36,7 +36,9 @@ public: cItem(void) : m_ItemType(E_ITEM_EMPTY), m_ItemCount(0), - m_ItemDamage(0) + m_ItemDamage(0), + m_CustomName(""), + m_Lore("") { } @@ -46,12 +48,16 @@ public: short a_ItemType, char a_ItemCount = 1, short a_ItemDamage = 0, - const AString & a_Enchantments = "" + const AString & a_Enchantments = "", + const AString & a_CustomName = "", + const AString & a_Lore = "" ) : m_ItemType (a_ItemType), m_ItemCount (a_ItemCount), m_ItemDamage (a_ItemDamage), - m_Enchantments(a_Enchantments) + m_Enchantments(a_Enchantments), + m_CustomName (a_CustomName), + m_Lore (a_Lore) { if (!IsValidItem(m_ItemType)) { @@ -69,7 +75,9 @@ public: m_ItemType (a_CopyFrom.m_ItemType), m_ItemCount (a_CopyFrom.m_ItemCount), m_ItemDamage (a_CopyFrom.m_ItemDamage), - m_Enchantments(a_CopyFrom.m_Enchantments) + m_Enchantments(a_CopyFrom.m_Enchantments), + m_CustomName (a_CopyFrom.m_CustomName), + m_Lore (a_CopyFrom.m_Lore) { } @@ -80,6 +88,8 @@ public: m_ItemCount = 0; m_ItemDamage = 0; m_Enchantments.Clear(); + m_CustomName = ""; + m_Lore = ""; } @@ -96,13 +106,16 @@ public: return ((m_ItemType <= 0) || (m_ItemCount <= 0)); } - + /* Returns true if this itemstack can stack with the specified stack (types match, enchantments etc.) ItemCounts are ignored! + */ bool IsEqual(const cItem & a_Item) const { return ( IsSameType(a_Item) && (m_ItemDamage == a_Item.m_ItemDamage) && - (m_Enchantments == a_Item.m_Enchantments) + (m_Enchantments == a_Item.m_Enchantments) && + (m_CustomName == a_Item.m_CustomName) && + (m_Lore == a_Item.m_Lore) ); } @@ -111,6 +124,16 @@ public: { return (m_ItemType == a_Item.m_ItemType) || (IsEmpty() && a_Item.IsEmpty()); } + + + bool IsBothNameAndLoreEmpty(void) const + { + return (m_CustomName.empty() && m_Lore.empty()); + } + + + bool IsCustomNameEmpty(void) const { return (m_CustomName.empty()); } + bool IsLoreEmpty(void) const { return (m_Lore.empty()); } /// Returns a copy of this item with m_ItemCount set to 1. Useful to preserve enchantments etc. on stacked items @@ -127,8 +150,10 @@ public: inline bool IsDamageable(void) const { return (GetMaxDamage() > 0); } - /// Returns true if this itemstack can stack with the specified stack (types match, enchantments etc.) ItemCounts are ignored! - bool IsStackableWith(const cItem & a_OtherStack) const; + /* Returns true if this itemstack can stack with the specified stack (types match, enchantments etc.) ItemCounts are ignored! + THIS FUNCTION IS OBSOLETE; USE ISEQUAL INSTEAD + */ + OBSOLETE bool IsStackableWith(const cItem & a_OtherStack) const { return IsEqual(a_OtherStack); } /// Returns true if the item is stacked up to its maximum stacking. bool IsFullStack(void) const; @@ -155,6 +180,8 @@ public: short m_ItemType; char m_ItemCount; short m_ItemDamage; + AString m_CustomName; + AString m_Lore; cEnchantments m_Enchantments; }; // tolua_end diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 68992155e..cb14bad4d 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -1647,7 +1647,7 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) return; } - // Load enchantments from the NBT: + // Load enchantments and custom display names from the NBT data: for (int tag = NBT.GetFirstChild(NBT.GetRoot()); tag >= 0; tag = NBT.GetNextSibling(tag)) { if ( @@ -1660,6 +1660,27 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) { a_Item.m_Enchantments.ParseFromNBT(NBT, tag); } + else if ((NBT.GetType(tag) == TAG_Compound) && (NBT.GetName(tag) == "display")) // Custom name and lore tag + { + for (int displaytag = NBT.GetFirstChild(tag); displaytag >= 0; displaytag = NBT.GetNextSibling(displaytag)) + { + if ((NBT.GetType(displaytag) == TAG_String) && (NBT.GetName(displaytag) == "Name")) // Custon name tag + { + a_Item.m_CustomName = NBT.GetString(displaytag); + } + else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag + { + AString Lore; + + for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings + { + AppendPrintf(Lore, "%s\n", NBT.GetString(loretag).c_str()); // Append the lore with a newline, used internally by MCS to display a new line in the client; don't forget to c_str ;) + } + + a_Item.m_Lore = Lore; + } + } + } } } @@ -1711,16 +1732,45 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item) WriteByte (a_Item.m_ItemCount); WriteShort(a_Item.m_ItemDamage); - if (a_Item.m_Enchantments.IsEmpty()) + if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty()) { WriteShort(-1); return; } - // Send the enchantments: + // Send the enchantments and custom names: cFastNBTWriter Writer; - const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; - a_Item.m_Enchantments.WriteToNBTCompound(Writer, TagName); + if (!a_Item.m_Enchantments.IsEmpty()) + { + const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; + a_Item.m_Enchantments.WriteToNBTCompound(Writer, TagName); + } + if (!a_Item.IsBothNameAndLoreEmpty()) + { + Writer.BeginCompound("display"); + if (!a_Item.IsCustomNameEmpty()) + { + Writer.AddString("Name", a_Item.m_CustomName.c_str()); + } + if (!a_Item.IsLoreEmpty()) + { + Writer.BeginList("Lore", TAG_String); + + AStringVector Decls = StringSplit(a_Item.m_Lore, "\n"); + for (AStringVector::const_iterator itr = Decls.begin(), end = Decls.end(); itr != end; ++itr) + { + if (itr->empty()) + { + // The decl is empty (two \ns), ignore + continue; + } + Writer.AddString("", itr->c_str()); + } + + Writer.EndList(); + } + Writer.EndCompound(); + } Writer.Finish(); AString Compressed; CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index a721e6b7e..df3687fda 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -89,6 +89,9 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA Slot.m_ItemCount -= DraggingItem.m_ItemCount; DraggingItem.m_ItemType = Slot.m_ItemType; DraggingItem.m_ItemDamage = Slot.m_ItemDamage; + DraggingItem.m_Enchantments = Slot.m_Enchantments; + DraggingItem.m_CustomName = Slot.m_CustomName; + DraggingItem.m_Lore = Slot.m_Lore; if (Slot.m_ItemCount <= 0) { @@ -105,6 +108,10 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA Slot.m_ItemCount++; Slot.m_ItemDamage = DraggingItem.m_ItemDamage; DraggingItem.m_ItemCount--; + + Slot.m_Enchantments = DraggingItem.m_Enchantments; + Slot.m_CustomName = DraggingItem.m_CustomName; + Slot.m_Lore = DraggingItem.m_Lore; } if (DraggingItem.m_ItemCount <= 0) {