Ru-MaNGOS

Ru-MaNGOS (http://mangos.ytdb.ru/index.php)
-   Патчи на рассмотрении (http://mangos.ytdb.ru/forumdisplay.php?f=49)
-   -   [fix] Ошибка клиента 132 при смене экипировки встроенным менеджером (http://mangos.ytdb.ru/showthread.php?t=2794)

Warlord123 01.11.2010 12:35

[fix] Ошибка клиента 132 при смене экипировки встроенным менеджером
 
Вложений: 1
При использовании встроенного в клиент менеджера экипировки
возникает проблема при следующих условиях:
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.

Vladimir 01.11.2010 14:48

Можно добавить опциональный аругмент : , uint32* pProblematicItemId)
и предавать его по цепочке Can* функций в глубь до ошибки, где

if (pProblematicItemId)
*pProblematicItemId = gemid -- или собствеено itemId

тогда можно будет значение из него будет передать в
SendEquipError( uint8 msg, Item* pItem, Item *pItem2, uint32 itemid) -- как itemid

Фактически тогда это значение можно будет использовать во всех случаях дополнительных данных в SendEquipError

Только это видимо потребует кучу мест для выставлния значений :(


Текущее время: 17:17. Часовой пояс GMT +3.

ru-mangos.ru - Русское сообщество MaNGOS