Güvenli Quest Reload

  • Konuyu açan Konuyu açan Darqhues
  • Açılış Tarihi Açılış Tarihi
  • Yanıt Yanıt 1
  • Gösterim Gösterim 79

Darqhues

Üye
Üye
Mesaj
87
Çözümler
3
Beğeni
37
Puan
714
Ticaret Puanı
0
Merhaba, özellikle kalabalık sunucularında reload q çekilmez. Kanal çökmelerine sebep olur, eşya kaybına sebep olur, zindanların patlamasına sebep olur. Yazdığım bu sistem bu sorunların hiçbir şekilde yaşanmamasını sağlayan bir sistemdir. Reload Q komutu p2p komutu değildir. Ancak bu sistemle artık p2p komutudur. Yani tek core üzerinde yazmanız diğer corelerde de etki edecektir. Rahatlıkla kullanabilirsiniz. 1500 online ile denenmiştir. Ücretsiz paylaşıyorum.


Önce neden çöktüğüne bakalım;

  • Açık quest penceresi: Reload() içindeki lua_close(L) bütün Lua ortamını kapatıyor. NPC menüsü, select, input ya da wait adımında bekleyen oyuncu cevap verince sunucu kapatılmış ortama yazıyor (CQuestManager::Select → lua_pushnumber çökmesi).
  • Zindan zamanlayıcıları: m_mapTimerID.clear() zamanlayıcı numaralarını sıfırlıyor. Çalışan zamanlayıcılar eski numarayla kalıyor; yenilemeden sonra yanlış scripte gidip Lua hatası veriyor.
  • Oyuncusuz script: server_timer hata verince SendScript boş karakterin GetDesc()'ini çağırıyor (CEntity::GetDesc (this=0x0) çökmesi).
  • Tek kanal: /reload q sadece komutun yazıldığı core'u yeniliyordu.




common/service.h

EKLE;

Kod:
Genişlet Daralt Kopyala
#define TETRA_SAFE_QUEST_RELOAD

game/src/packet.h

ARAT;

Kod:
Genişlet Daralt Kopyala
HEADER_GG_LOGIN = 1

GG paketlerinin en altına ekle. (Numaraya dikkat edin, GG paketlerinin kullanmadığı bir numara olmalıdır.

Kod:
Genişlet Daralt Kopyala
#ifdef TETRA_SAFE_QUEST_RELOAD
    HEADER_GG_RELOAD_QUEST                = 40,
#endif

game/src/packet_info.cpp

ARA;

Kod:
Genişlet Daralt Kopyala
CPacketInfoGG::CPacketInfoGG()
{

Fonksiyonun sonuna ekle;

Kod:
Genişlet Daralt Kopyala
#ifdef TETRA_SAFE_QUEST_RELOAD
    Set (HEADER_GG_RELOAD_QUEST,    sizeof (BYTE),    "ReloadQuest",    false);
#endif

game/src/input_p2p.cpp

ARA;

Kod:
Genişlet Daralt Kopyala
int CInputP2P::Analyze (LPDESC d, BYTE bHeader, const char* c_pData)

İçindeki switch (bHeader) bloğunu bulun. Dosyanın başında #include "questmanager.h" olduğundan emin olun.

EKLE;

Kod:
Genişlet Daralt Kopyala
#ifdef TETRA_SAFE_QUEST_RELOAD
        case HEADER_GG_RELOAD_QUEST:
            sys_log (0, "QUEST_RELOAD: diger core'dan istek geldi");
            quest::CQuestManager::instance().Reload();
            break;
#endif

game/src/cmd_gm.cpp

ARA;

Kod:
Genişlet Daralt Kopyala
            case 'q':
                ch->ChatPacket (CHAT_TYPE_INFO, "Reloading quest.");
                quest::CQuestManager::instance().Reload();

ALTINA EKLE (BREAK satırından hemen önce)

Kod:
Genişlet Daralt Kopyala
#ifdef TETRA_SAFE_QUEST_RELOAD
                {
                    BYTE bHeader = HEADER_GG_RELOAD_QUEST;
                    P2P_MANAGER::instance().Send (&bHeader, sizeof (BYTE));
                    ch->ChatPacket (CHAT_TYPE_INFO, "Quest reloaded across all channels.");
                }
#endif


game/src/questmanager.cpp

ARA;

Kod:
Genişlet Daralt Kopyala
    void CQuestManager::Reload()
    {
        lua_close (L);

DEĞİŞTİR;

Kod:
Genişlet Daralt Kopyala
    void CQuestManager::Reload()
    {
#ifdef TETRA_SAFE_QUEST_RELOAD
        int iClosedQuest = 0;
        for (PCMap::iterator itPC = m_mapPC.begin(); itPC != m_mapPC.end(); ++itPC)
        {
            PC& rkPC = itPC->second;
            if (!rkPC.IsRunning())
                continue;

            QuestState* pkState = rkPC.GetRunningQuestState();
            if (pkState)
                CloseState (*pkState);    
            rkPC.CancelRunning();
            ++iClosedQuest;

            LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID (itPC->first);
            if (!ch)
                continue;

            LPCHARACTER npc = ch->GetQuestNPC();
            if (npc && !npc->IsPC() && npc->GetQuestNPCID() == ch->GetPlayerID())
                npc->SetQuestNPCID (0);
            ch->SetQuestNPCID (0);

            if (ch->GetDesc())
            {
                const char* c_szDone = "[DONE]";
                struct ::packet_script ps;
                ps.header = HEADER_GC_SCRIPT;
                ps.skin = QUEST_SKIN_NOWINDOW;
                ps.src_size = strlen (c_szDone);
                ps.size = ps.src_size + sizeof (struct ::packet_script);

                TEMP_BUFFER buf;
                buf.write (&ps, sizeof (struct ::packet_script));
                buf.write (c_szDone, ps.src_size);
                ch->GetDesc()->Packet (buf.read_peek(), buf.size());
            }
        }
        sys_log (0, "QUEST_RELOAD: %d acik quest kapatildi", iClosedQuest);
#endif
        lua_close (L);

Aynı fonksiyonda ara;

Kod:
Genişlet Daralt Kopyala
    m_mapTimerID.clear();

DEĞİŞTİR;

Kod:
Genişlet Daralt Kopyala
#ifndef TETRA_SAFE_QUEST_RELOAD
        m_mapTimerID.clear(); 
#endif

Aynı fonksiyonun sonunda ARA;

Kod:
Genişlet Daralt Kopyala
            m_mapNPC[dwVnum].Set (dwVnum, buf);
        }

Altına ekle (fonksiyonun kapanış } işaretinden önce)

Kod:
Genişlet Daralt Kopyala
#ifdef TETRA_SAFE_QUEST_RELOAD
        for (map<string, unsigned int>::iterator itTimer = m_mapTimerID.begin(); itTimer != m_mapTimerID.end(); ++itTimer)
            m_mapNPC[itTimer->second].Set (itTimer->second, itTimer->first);
#endif


game/src/questmanager.cpp

ARA;

Kod:
Genişlet Daralt Kopyala
GetCurrentCharacterPtr()->GetDesc()->Packet (buf.read_peek(), buf.size());

DEĞİŞTİR;

Kod:
Genişlet Daralt Kopyala
#ifdef TETRA_SAFE_QUEST_RELOAD
        LPCHARACTER pkScriptChr = GetCurrentCharacterPtr();
        if (!pkScriptChr || !pkScriptChr->GetDesc())
        {
            ClearScript();
            return;
        }
        pkScriptChr->GetDesc()->Packet (buf.read_peek(), buf.size());
#else
        GetCurrentCharacterPtr()->GetDesc()->Packet (buf.read_peek(), buf.size());
#endif
 
Geri
Üst