Добавлено через 2 часа 52 минуты
Немного поясню, почему же этот кусок кода позволяет делать накрутку
При вызове CancelPlayerRaceBuff передаётся текущий уровень дэбафа, а поскольку внутри есть проверка текущего уровня и снимаемого(то что передали), то эта проверка будет всегда валидна
По сути, даже если снимать легально, то дэбаф будет снят дважды, при проверке и в функции которая более полно реализует снятие дэбафа
Так же в этом месте не хватает проверки IsUseReleaseRaceBuffPotion, это даёт возможность повторного снятия дэбафа, даже если он уже снят на постоянно основе
Последний раз редактировалось g00dw1n; 04.06.2017 в 22:42.
Причина: Добавлено сообщение
Но однажды, пришли злые программисты и дописали её:
Код:
sprintf_s(DstBuf, m_Param.GetCharNameW());
Функции стало плохо, из-за неё стал рушится весь остальной мир, поскольку программисты, которые её дописывали, не знали как работает varargs, а ведь достаточно было прочитать древние руны и написать вот так:
Код:
sprintf_s(DstBuf, "%s", m_Param.GetCharNameW());
// Правда я хз на кой хер это написали, ибо дальше этот буффер не используется
Последний раз редактировалось g00dw1n; 12.06.2017 в 15:53.
Когда у нас достигнут лимит по квестам от NPC, то квест добавляется вот в сюды (запоминаем этот финт):
Код:
this->m_QuestMgr.m_pTempHappenEvent
Размер ограничен 3 элементами.
После освобождения места для квеста, мы, как честные граждане РФ, берём этот квест, но мы же помним кто корейцы, да? Поэтому обращаем наш взор на функцию, которая отвечает за диалог, в нашем случае это завершение квеста и получение следующего:
Код:
CPlayer::Emb_CompleteQuest
Где-то внизу функции видим имеем такой псевдокод:
Код:
if ( pNextQuestFld )
{
pSlotData = &this->m_Param.m_QuestDB.m_List[(unsigned __int8)byQuestDBSlot];
pSlotData->byQuestType = Dst.byQuestType;
pSlotData->wIndex = pNextQuestFld->m_dwIndex;
pSlotData->dwPassSec = 0;
for ( k = 0; k < 3; ++k )
{
if ( pNextQuestFld->m_ActionNode[k].m_nActType != -1 )
pSlotData->wNum[k] = 0;
}
CUserDB::Update_QuestInsert(this->m_pUserDB, byQuestDBSlot, pSlotData);
CPlayer::SendMsg_InsertNextQuest(this, byQuestDBSlot, pSlotData);
}
for ( l = 0; l < 3; ++l )
{
if ( _happen_event_cont::isset(&this->m_QuestMgr.m_pTempHappenEvent[l]) )
{
memcpy_0(&this->m_QuestMgr.m_LastHappenEvent, &this->m_QuestMgr.m_pTempHappenEvent[l], 0x18ui64);
CPlayer::Emb_StartQuest(this, -1, &this->m_QuestMgr.m_pTempHappenEvent[l]);
if ( this->m_QuestMgr.m_pTempHappenEvent[l].m_QtHpType == 8 )
{
CPlayerDB::SetMaxLevel(&this->m_Param, 50);
if ( this->m_pUserDB )
CUserDB::Update_MaxLevel(this->m_pUserDB, 50);
}
_happen_event_cont::init(&this->m_QuestMgr.m_pTempHappenEvent[l]);
}
}
И тут мы вспоминаем про тот финт ушами с
Код:
this->m_QuestMgr.m_pTempHappenEvent
и получается что по завершению квеста нам не только отсыпают следующий квест, но и пытаются выдать квесты которые мы пытались взять, но не шмогли. Ну а поскольку мы граждане порядошные, и имеем место для квестов, то нам их выдают.
Как мне кажется, более правильным будет убрать этот финт из функции
Код:
CPlayer::Emb_CreateNPCQuest
Но можно попробовать сделать вот так:
Код:
if ( pNextQuestFld )
{
pSlotData = &this->m_Param.m_QuestDB.m_List[(unsigned __int8)byQuestDBSlot];
pSlotData->byQuestType = Dst.byQuestType;
pSlotData->wIndex = pNextQuestFld->m_dwIndex;
pSlotData->dwPassSec = 0;
for ( k = 0; k < 3; ++k )
{
if ( pNextQuestFld->m_ActionNode[k].m_nActType != -1 )
pSlotData->wNum[k] = 0;
}
CUserDB::Update_QuestInsert(this->m_pUserDB, byQuestDBSlot, pSlotData);
CPlayer::SendMsg_InsertNextQuest(this, byQuestDBSlot, pSlotData);
}
else {
for ( l = 0; l < 3; ++l )
{
if ( _happen_event_cont::isset(&this->m_QuestMgr.m_pTempHappenEvent[l]) )
{
memcpy_0(&this->m_QuestMgr.m_LastHappenEvent, &this->m_QuestMgr.m_pTempHappenEvent[l], 0x18ui64);
CPlayer::Emb_StartQuest(this, -1, &this->m_QuestMgr.m_pTempHappenEvent[l]);
if ( this->m_QuestMgr.m_pTempHappenEvent[l].m_QtHpType == 8 )
{
CPlayerDB::SetMaxLevel(&this->m_Param, 50);
if ( this->m_pUserDB )
CUserDB::Update_MaxLevel(this->m_pUserDB, 50);
}
_happen_event_cont::init(&this->m_QuestMgr.m_pTempHappenEvent[l]);
}
}
}
Почему в питере было тепло? Патамушта мой пукан горел от этой темы, точнее от того косяка который сделали.
Собственно с клиента данные приходят валидные, далее в функции:
Код:
CUnmannedTraderUserInfo::ReRegist
Заполняется "таска", которая будет выполнена в отдельном треде
Структура этой задачи такая:
Код:
struct _qry_case_unmandtrader_re_registsingleitem
{
struct __list
{
char byProcRet;
bool bRegist;
unsigned __int16 wItemSerial;
unsigned int dwTax;
unsigned int dwListIndex;
char byClass1;
char byClass2;
char byClass3;
unsigned int dwPrice;
unsigned int dwRegistSerial;
char byUpdateState;
};
char byType;
unsigned __int16 wInx;
char byNum;
unsigned int dwOwnerSerial;
__list List[10];
};
Как мы видим, в этой структуре нет ни одного поля, которое бы отвечало за кол-во предметов которое будет зарегистрировано. Смекаешь? Они не апдейтят кол-во предметов в стеке, они просто обновляют цену, время регистрации и стейт у зарегистрированного предмета.
Как это фиксить? Мне видится только 1 нормальный способ, это добавить инфу, о кол-ве предметов в стеке, в структуру задачи что выше, но для этого нужно восстановить не малое кол-во функций чтобы это поменять.
Но! У меня есть костыльные варианты решения:
Способ номер раз:
Вешаемся на функцию
Код:
CUnmannedTraderController::UpdateReRegist
И перед выполнением функции
Код:
CRFWorldDatabase::Update_UnmannedTraderReRegist
Дёргаем ячейку по серийнику с инвентаря и уже из ячейки берём сколько есть, но тут есть 1 грабля, на которую можно наступить - перс может быть уже не в онлайне в этот момент и тогда надо делать запрос в базу чтобы достать нужное кол-во. А после квеста с получением кол-ва предметов в стеке - делаем запрос в базу, чтобы это обновить
Способ номер два:
Вешаемся на функцию
Код:
CUnmannedTraderUserInfo::ReRegist
и делаем отмену регистрации, как это сделано вот в этой функции
Код:
CUnmannedTraderUserInfo::CancelRegist
Способ номер 3:
Вешаемся на функцию
Код:
CUnmannedTraderUserInfo::ReRegist
и не делаем нихуя, вообще, вот прям совсем
ибо, нету ручек - нет конфеток
Последний раз редактировалось g00dw1n; 30.06.2017 в 02:29.