// Enchantments.cpp // Implements the cEnchantments class representing a storage for item enchantments and stored-enchantments #include "Globals.h" #include "Enchantments.h" #include "WorldStorage/FastNBT.h" cEnchantments::cEnchantments(void) { // Nothing needed yet, but the constructor needs to be declared and impemented in order to be usable } cEnchantments::cEnchantments(const AString & a_StringSpec) { AddFromString(a_StringSpec); } void cEnchantments::AddFromString(const AString & a_StringSpec) { // Add enchantments in the stringspec; if a specified enchantment already exists, overwrites it // Split the StringSpec into separate declarations, each in the form "id=lvl": AStringVector Decls = StringSplit(a_StringSpec, ";"); for (AStringVector::const_iterator itr = Decls.begin(), end = Decls.end(); itr != end; ++itr) { // Split each declaration into the id and lvl part: if (itr->empty()) { // The decl is empty (may happen if there's an extra semicolon at the end), ignore silently continue; } AStringVector Split = StringSplitAndTrim(*itr, "="); if (Split.size() != 2) { // Malformed decl LOG("%s: Malformed enchantment decl: \"%s\", skipping.", __FUNCTION__, itr->c_str()); continue; } int id = atoi(Split[0].c_str()); if ((id == 0) && (Split[0] != "0")) { id = StringToEnchantmentID(Split[0]); } int lvl = atoi(Split[1].c_str()); if ( ((id <= 0) && (Split[0] != "0")) || ((lvl == 0) && (Split[1] != "0")) ) { // Numbers failed to parse LOG("%s: Failed to parse enchantment declaration for numbers: \"%s\" and \"%s\", skipping.", __FUNCTION__, Split[0].c_str(), Split[1].c_str() ); continue; } SetLevel(id, lvl); } // for itr - Decls[] } AString cEnchantments::ToString(void) const { // Serialize all the enchantments into a string AString res; for (cEnchantments::cMap::const_iterator itr = m_Enchantments.begin(), end = m_Enchantments.end(); itr != end; ++itr) { AppendPrintf(res, "%d=%d;", itr->first, itr->second); } // for itr - m_Enchantments[] return res; } int cEnchantments::GetLevel(int a_EnchantmentID) const { // Return the level for the specified enchantment; 0 if not stored cMap::const_iterator itr = m_Enchantments.find(a_EnchantmentID); if (itr != m_Enchantments.end()) { return itr->second; } // Not stored, return zero return 0; } void cEnchantments::SetLevel(int a_EnchantmentID, int a_Level) { // Sets the level for the specified enchantment, adding it if not stored before or removing it if level <= 0 if (a_Level == 0) { // Delete enchantment, if present: cMap::iterator itr = m_Enchantments.find(a_EnchantmentID); if (itr != m_Enchantments.end()) { m_Enchantments.erase(itr); } } else { // Add / overwrite enchantment m_Enchantments[a_EnchantmentID] = a_Level; } } void cEnchantments::Clear(void) { m_Enchantments.clear(); } bool cEnchantments::IsEmpty(void) const { return m_Enchantments.empty(); } int cEnchantments::StringToEnchantmentID(const AString & a_EnchantmentName) { struct { int m_Value; const char * m_Name; } EnchantmentNames[] = { { enchProtection, "Protection"}, { enchFireProtection, "FireProtection"}, { enchFeatherFalling, "FeatherFalling"}, { enchBlastProtection, "BlastProtection"}, { enchProjectileProtection, "ProjectileProtection"}, { enchRespiration, "Respiration"}, { enchAquaAffinity, "AquaAffinity"}, { enchThorns, "Thorns"}, { enchSharpness, "Sharpness"}, { enchSmite, "Smite"}, { enchBaneOfArthropods, "BaneOfArthropods"}, { enchKnockback, "Knockback"}, { enchFireAspect, "FireAspect"}, { enchLooting, "Looting"}, { enchEfficiency, "Efficiency"}, { enchSilkTouch, "SilkTouch"}, { enchUnbreaking, "Unbreaking"}, { enchFortune, "Fortune"}, { enchPower, "Power"}, { enchPunch, "Punch"}, { enchFlame, "Flame"}, { enchInfinity, "Infinity"}, } ; for (int i = 0; i < ARRAYCOUNT(EnchantmentNames); i++) { if (NoCaseCompare(EnchantmentNames[i].m_Name, a_EnchantmentName) == 0) { return EnchantmentNames[i].m_Value; } } // for i - EnchantmentNames[] return -1; } bool cEnchantments::operator ==(const cEnchantments & a_Other) const { return m_Enchantments == a_Other.m_Enchantments; } bool cEnchantments::operator !=(const cEnchantments & a_Other) const { return m_Enchantments != a_Other.m_Enchantments; } void cEnchantments::WriteToNBTCompound(cFastNBTWriter & a_Writer, const AString & a_ListTagName) const { // Write the enchantments into the specified NBT writer // begin with the LIST tag of the specified name ("ench" or "StoredEnchantments") a_Writer.BeginList(a_ListTagName, TAG_Compound); for (cMap::const_iterator itr = m_Enchantments.begin(), end = m_Enchantments.end(); itr != end; ++itr) { a_Writer.BeginCompound(""); a_Writer.AddShort("id", itr->first); a_Writer.AddShort("lvl", itr->second); a_Writer.EndCompound(); } // for itr - m_Enchantments[] a_Writer.EndList(); } void cEnchantments::ParseFromNBT(const cParsedNBT & a_NBT, int a_EnchListTagIdx) { // Read the enchantments from the specified NBT list tag (ench or StoredEnchantments) // Verify that the tag is a list: if (a_NBT.GetType(a_EnchListTagIdx) != TAG_List) { LOGWARNING("%s: Invalid EnchListTag type: exp %d, got %d. Enchantments not parsed", __FUNCTION__, TAG_List, a_NBT.GetType(a_EnchListTagIdx) ); ASSERT(!"Bad EnchListTag type"); return; } // Verify that the list is of Compounds: if (a_NBT.GetChildrenType(a_EnchListTagIdx) != TAG_Compound) { LOGWARNING("%s: Invalid NBT list children type: exp %d, got %d. Enchantments not parsed", __FUNCTION__, TAG_Compound, a_NBT.GetChildrenType(a_EnchListTagIdx) ); ASSERT(!"Bad EnchListTag children type"); return; } Clear(); // Iterate over all the compound children, parse an enchantment from each: for (int tag = a_NBT.GetFirstChild(a_EnchListTagIdx); tag >= 0; tag = a_NBT.GetNextSibling(tag)) { // tag is the compound inside the "ench" list tag ASSERT(a_NBT.GetType(tag) == TAG_Compound); // Search for the id and lvl tags' values: int id = -1, lvl = -1; for (int ch = a_NBT.GetFirstChild(tag); ch >= 0; ch = a_NBT.GetNextSibling(ch)) { if (a_NBT.GetType(ch) != TAG_Short) { continue; } if (a_NBT.GetName(ch) == "id") { id = a_NBT.GetShort(ch); } else if (a_NBT.GetName(ch) == "lvl") { lvl = a_NBT.GetShort(ch); } } // for ch - children of the compound tag if ((id == -1) || (lvl <= 0)) { // Failed to parse either the id or the lvl, skip this compound continue; } // Store the enchantment: m_Enchantments[id] = lvl; } // for tag - children of the ench list tag }