При использовании встроенного в клиент менеджера экипировки
возникает проблема при следующих условиях:
1. Персонаж сохранил набор экипировки с 3 джевеловскими камнями (ItemLimitCategory=2).
2. Одевает другой набор вещей, тоже с двеловскими камнями.
3. При попытке переключиться на набор из п.1 происходит падение клиента с ошибкой 132.
Ошибка возникает при формировании пакета от сервера клиенту в процедуре
Код:
void Player::SendEquipError( uint8 msg, Item* pItem, Item *pItem2, uint32 itemid /*= 0*/ ) const
.........
case EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED_IS:
case EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_SOCKETED_EXCEEDED_IS:
case EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED_IS:
{
ItemPrototype const* proto = pItem ? pItem->GetProto() : sObjectMgr.GetItemPrototype(itemid);
data << uint32(proto ? proto->ItemLimitCategory : 0);
break;
}
.........
Клиенту передается proto->ItemLimitCategory, что не всегда верно. При ошибке с камнями должен передаваться
не ItemLimitCategory предмета(который в большинстве случаев 0), а именно ItemLimitCategory камня, который не дает одеть предмет.
Патчик.
Код:
index 149aaa0..7b17437 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -12295,7 +12295,35 @@ void Player::SendEquipError( uint8 msg, Item* pItem, Item *pItem2, uint32 itemid
case EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED_IS:
{
ItemPrototype const* proto = pItem ? pItem->GetProto() : sObjectMgr.GetItemPrototype(itemid);
- data << uint32(proto ? proto->ItemLimitCategory : 0);
+ uint32 LimitCategory=proto ? proto->ItemLimitCategory : 0;
+ if (pItem)
+ // check unique-equipped on gems
+ for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)
+ {
+ uint32 enchant_id = pItem->GetEnchantmentId(EnchantmentSlot(enchant_slot));
+ if(!enchant_id)
+ continue;
+ SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
+ if(!enchantEntry)
+ continue;
+
+ ItemPrototype const* pGem = ObjectMgr::GetItemPrototype(enchantEntry->GemID);
+ if(!pGem)
+ continue;
+
+ // include for check equip another gems with same limit category for not equipped item (and then not counted)
+ uint32 gem_limit_count = !pItem->IsEquipped() && pGem->ItemLimitCategory
+ ? pItem->GetGemCountWithLimitCategory(pGem->ItemLimitCategory) : 1;
+
+ if( msg == CanEquipUniqueItem(pGem, pItem->GetSlot(),gem_limit_count))
+ {
+ LimitCategory=pGem->ItemLimitCategory;
+ break;
+
+ }
+ }
+
+ data << uint32(LimitCategory);
break;
}
default:
Реализация решает проблему, но явно "хаком", так как приходиться восстанавливать информацию
о том, какая именно ItemLimitCategory вызвала проблему.
Функция
uint8 Player::CanEquipUniqueItem(Item* pItem, uint8 eslot, uint32 limit_count)возвращает
только код ошибки, без источника возникновения.
Варианты правильного решения:
1. из Player::CanEquipUniqueItem(Item* pItem, uint8 eslot, uint32 limit_count) как-то передавать данные о категории
из функции Player::SendEquipError( uint8 msg... через структуру или переменную.
2. Выделить из Player::CanEquipUniqueItem(Item* pItem, uint8 eslot, uint32 limit_count) код проверки
камней, который будет сообщать данные об ошибке и категории предмета, вызвавшего ошибку.
Выделенную функцию вызывать из Player::CanEquipUniqueItem(Item* pItem.. и из Player::SendEquipError.