Yardım Sonitex DB Sıkıntısı

Konu sahibi bu konuda soru soruyor. Sorusu ile ilgili bilgisi olanların yanıtlamasını bekliyor.

PDx

Üye
Üye
Mesaj
7
Beğeni
0
Puan
38
Ticaret Puanı
0
Razu V5 altyapısına, Sonitex konusundaki sistemi entegre etmeye çalışıyorum. Birçok hatayı geçerek kodu belli bir noktaya getirdim ancak şu anki hata herhangi bir syserr basmıyor.
Örnek olarak bir pazar oluşturdum ve içerisine 1 adet item listeledim. Farklı bir account üzerinden bu itemi satın aldım ve doğal olarak pazar kapandı ve yok oldu. Bu aşamadan sonra kapanan pazar sahibi olan account yeni bir pazar açamıyor ve char_item.cpp içerisindeki if (IsPrivateShopOwner()) satırına girerek "Close your current personal shop before opening a new one." hatasını basıyor.
Bu hatayı görünce sıkıntının server source kaynaklı olduğunu düşündüm. DB kodlarını kurcalarken player DB içerisine eklemiş olduğum private_shop tablosuna verinin geç yazıldığını fark ettim.
Örneğin pazarı açıyorum, tabloya sırasıyla (owner_id, owner_name, state, title, title_type, vnum, x, y, map_index, channel, port, gold, cheque, page_count, premium_time) bilgileri gecikmeli olarak ekleniyor ve state kısmı OPEN olarak işleniyor. Pazar item satın alınıp kapandıktan sonra bu stateyi güncellemeden yok oluyor yaklaşık 1 dakika sonra DB ye state CLOSED olarak güncellemeyi ekliyor. Anladığım kadarıyla bu işlemleri önce cache üzerinden gerçekleştirdiği için DB ye ihtiyaç duymadan bu noktaya kadar gelebiliyor iş.
Örnek 1 satırlık private_shop tablosu kayıtı:
1 PDx CLOSED PAZAR 0 30000 960004 271937 41 1 13000 1111 0 1 0

private_shop_item tablosuna ise pazarı açsam da kapasam da hiçbir veri işlenmiyor (tahminimce böyle olması gerekiyor ama emin değilim).
Rehberin ClientManagerBoot.cpp kısmındaki detaylarını kullandığım source TXT proto olduğu için gerçekleştirmemiştim ama vnum_range olayı bu soruna sebep olur mu kestiremiyorum. ClientManager.cpp içerisine bir girişmeyi düşündüm ama sıkıntının nereden kaynaklandığını tam anlamadığım için dokunmayayım dedim.
Elimde ekleyebileceğim sadece syslog var belki buradan siz de bir çıkarım yapabilirsiniz.
syslog:
Genişlet Daralt Kopyala
Jun  4 22:09:11 :: PRIVATE_SHOP: Building private shop 3
Jun  4 22:09:11 :: Re-creating private shop for owner 3
Jun  4 22:09:11 :: PRIVATE_SHOP: Added item 10000658 pos 17 vnum 189 to private shop 3
Jun  4 22:09:11 :: PRIVATE_SHOP: Private shop 3 successfully created
Jun  4 22:09:11 :: PRIVATE_SHOP: Private shop 3 successfully built
Jun  4 22:09:13 :: [    10550] return 0/0/1 async 0/0/0
Jun  4 22:09:18 :: [    10600] return 0/0/0 async 0/0/0
Jun  4 22:09:23 :: [    10650] return 0/0/0 async 0/0/0
Jun  4 22:09:28 :: [    10700] return 0/0/0 async 0/0/0
Jun  4 22:09:33 :: [    10750] return 0/0/0 async 0/0/0
Jun  4 22:09:38 :: [    10800] return 0/0/1 async 0/0/0
Jun  4 22:09:43 :: [    10850] return 0/0/0 async 0/0/0
Jun  4 22:09:48 :: [    10900] return 0/0/0 async 0/0/0
Jun  4 22:09:53 :: [    10950] return 0/0/0 async 0/0/0
Jun  4 22:09:58 :: [    11000] return 0/0/0 async 0/0/0
Jun  4 22:10:03 :: [    11050] return 0/0/0 async 0/0/0
Jun  4 22:10:08 :: [    11100] return 0/0/0 async 0/0/0
Jun  4 22:10:13 :: [    11150] return 0/0/0 async 0/0/0
Jun  4 22:10:18 :: [    11200] return 0/0/0 async 0/0/0
Jun  4 22:10:23 :: [    11250] return 0/0/0 async 0/0/0
Jun  4 22:10:28 :: [    11300] return 0/0/0 async 0/0/0
Jun  4 22:10:33 :: [    11350] return 0/0/0 async 0/0/0
Jun  4 22:10:38 :: [    11400] return 0/0/0 async 0/0/0
Jun  4 22:10:43 :: [    11450] return 0/0/0 async 0/0/0
Jun  4 22:10:48 :: [    11500] return 0/0/0 async 0/0/0
Jun  4 22:10:53 :: [    11550] return 0/0/0 async 0/0/0
Jun  4 22:10:58 :: [    11600] return 0/0/0 async 0/0/0
Jun  4 22:11:03 :: [    11650] return 0/0/0 async 0/0/0
Jun  4 22:11:08 :: [    11700] return 0/0/0 async 0/0/0
Jun  4 22:11:13 :: [    11750] return 0/0/0 async 0/0/0
Jun  4 22:11:18 :: [    11800] return 0/0/0 async 0/0/0
Jun  4 22:11:23 :: [    11850] return 0/0/0 async 0/0/0
Jun  4 22:11:28 :: [    11900] return 0/0/0 async 0/0/0
Jun  4 22:11:33 :: [    11950] return 0/0/0 async 0/0/0
Jun  4 22:11:38 :: [    12000] return 0/0/0 async 0/0/0
Jun  4 22:11:43 :: [    12050] return 0/0/0 async 0/0/0
Jun  4 22:11:48 :: [    12100] return 0/0/0 async 0/0/0
Jun  4 22:11:53 :: [    12150] return 0/0/0 async 0/0/0
Jun  4 22:11:58 :: [    12200] return 0/0/0 async 0/0/0
Jun  4 22:12:03 :: [    12250] return 0/0/0 async 0/0/0
Jun  4 22:12:08 :: [    12300] return 0/0/0 async 0/0/0
Jun  4 22:12:13 :: [    12350] return 0/0/0 async 0/0/0
Jun  4 22:12:18 :: [    12400] return 0/0/0 async 0/0/0
Jun  4 22:12:23 :: [    12450] return 0/0/0 async 0/0/0
Jun  4 22:12:28 :: [    12500] return 0/0/0 async 0/0/0
Jun  4 22:12:33 :: [    12550] return 0/0/0 async 0/0/0
Jun  4 22:12:38 :: [    12600] return 0/0/0 async 0/0/0
Jun  4 22:12:43 :: [    12650] return 0/0/1 async 0/0/0
Jun  4 22:12:48 :: [    12700] return 0/0/0 async 0/0/0
Jun  4 22:12:53 :: [    12750] return 0/0/0 async 0/0/0
Jun  4 22:12:58 :: [    12800] return 0/0/0 async 0/0/0
Jun  4 22:13:03 :: [    12850] return 0/0/0 async 0/0/0
Jun  4 22:13:08 :: [    12900] return 0/0/0 async 0/0/0
Jun  4 22:13:13 :: [    12950] return 0/0/0 async 0/0/0
Jun  4 22:13:18 :: [    13000] return 0/0/0 async 0/0/0
Jun  4 22:13:23 :: [    13050] return 0/0/0 async 0/0/0
Jun  4 22:13:28 :: [    13100] return 0/0/0 async 0/0/0
Jun  4 22:13:33 :: [    13150] return 0/0/0 async 0/0/0
Jun  4 22:13:38 :: [    13200] return 0/0/0 async 0/0/0
Jun  4 22:13:43 :: [    13250] return 0/0/0 async 0/0/0
Jun  4 22:13:48 :: [    13300] return 0/0/0 async 0/0/0
Jun  4 22:13:53 :: [    13350] return 0/0/0 async 0/0/0
Jun  4 22:13:58 :: [    13400] return 0/0/0 async 0/0/0
Jun  4 22:14:03 :: [    13450] return 0/0/0 async 0/0/0
Jun  4 22:14:08 :: [    13500] return 0/0/0 async 0/0/0
Jun  4 22:14:13 :: [    13550] return 0/0/2 async 0/0/0
Jun  4 22:14:18 :: [    13600] return 0/0/0 async 0/0/0
Jun  4 22:14:23 :: [    13650] return 0/0/0 async 0/0/0
Jun  4 22:14:28 :: [    13700] return 0/0/0 async 0/0/0
Jun  4 22:14:33 :: [    13750] return 0/0/0 async 0/0/0
Jun  4 22:14:38 :: [    13800] return 0/0/0 async 0/0/0
Jun  4 22:14:43 :: [    13850] return 0/0/0 async 0/0/0
Jun  4 22:14:44 :: PRIVATE_SHOP: Buy request forwarded to game for private shop 3 customer 1 item pos 17 item 189 yang 1313 won 0
Jun  4 22:14:44 :: PRIVATE_SHOP: Item bought from private shop 3 pos 17 gold 1313 won 0 by pid 1
Jun  4 22:14:44 :: PRIVATE_SHOP: Despawning item empty private shop 3 by item sale
Jun  4 22:14:44 :: PRIVATE_SHOP: Sending despawn update to owner 3
Jun  4 22:14:48 :: [    13900] return 0/0/0 async 0/0/0
Jun  4 22:14:53 :: [    13950] return 0/0/0 async 0/0/0
Jun  4 22:14:58 :: [    14000] return 0/0/0 async 0/0/0
Jun  4 22:15:03 :: [    14050] return 0/0/0 async 0/0/0
Jun  4 22:15:08 :: [    14100] return 0/0/0 async 0/0/0
Jun  4 22:15:13 :: [    14150] return 0/0/0 async 0/0/0
Jun  4 22:15:18 :: [    14200] return 0/0/0 async 0/0/0
Jun  4 22:15:23 :: [    14250] return 0/0/0 async 0/0/0
Jun  4 22:15:28 :: [    14300] return 0/0/0 async 0/0/0
Jun  4 22:15:33 :: [    14350] return 0/0/0 async 0/0/0
Jun  4 22:15:38 :: [    14400] return 0/0/0 async 0/0/0
Jun  4 22:15:43 :: [    14450] return 0/0/0 async 0/0/0
Jun  4 22:15:48 :: [    14500] return 0/0/0 async 0/0/0
Jun  4 22:15:53 :: [    14550] return 0/0/0 async 0/0/0
Jun  4 22:15:58 :: [    14600] return 0/0/0 async 0/0/0
Jun  4 22:16:03 :: [    14650] return 0/0/0 async 0/0/0
Jun  4 22:16:08 :: [    14700] return 0/0/0 async 0/0/0
Jun  4 22:16:13 :: [    14750] return 0/0/0 async 0/0/0
Jun  4 22:16:18 :: [    14800] return 0/0/0 async 0/0/0
Jun  4 22:16:23 :: [    14850] return 0/0/0 async 0/0/0
Jun  4 22:16:28 :: [    14900] return 0/0/0 async 0/0/0
Jun  4 22:16:33 :: [    14950] return 0/0/0 async 0/0/0
Jun  4 22:16:38 :: [    15000] return 0/0/0 async 0/0/0
Jun  4 22:16:43 :: [    15050] return 0/0/0 async 0/0/0
Jun  4 22:16:48 :: [    15100] return 0/0/0 async 0/0/0
Jun  4 22:16:53 :: [    15150] return 0/0/0 async 0/0/0
Jun  4 22:16:58 :: [    15200] return 0/0/0 async 0/0/0
Jun  4 22:17:03 :: [    15250] return 0/0/0 async 0/0/0
Jun  4 22:17:08 :: [    15300] return 0/0/0 async 0/0/0
Jun  4 22:17:13 :: [    15350] return 0/0/0 async 0/0/0
Jun  4 22:17:18 :: [    15400] return 0/0/0 async 0/0/0
Jun  4 22:17:23 :: [    15450] return 0/0/0 async 0/0/0
Jun  4 22:17:28 :: [    15500] return 0/0/0 async 0/0/0
Jun  4 22:17:33 :: [    15550] return 0/0/0 async 0/0/0
Jun  4 22:17:38 :: [    15600] return 0/0/1 async 0/0/0
Jun  4 22:17:43 :: [    15650] return 0/0/0 async 0/0/0
Jun  4 22:17:48 :: [    15700] return 0/0/0 async 0/0/0
Jun  4 22:17:53 :: [    15750] return 0/0/0 async 0/0/0
Jun  4 22:17:58 :: [    15800] return 0/0/0 async 0/0/0
Jun  4 22:18:03 :: [    15850] return 0/0/0 async 0/0/0
Jun  4 22:18:08 :: [    15900] return 0/0/0 async 0/0/0
Jun  4 22:18:13 :: [    15950] return 0/0/0 async 0/0/0
Jun  4 22:18:18 :: [    16000] return 0/0/0 async 0/0/0
Jun  4 22:18:23 :: [    16050] return 0/0/0 async 0/0/0
Jun  4 22:18:28 :: [    16100] return 0/0/0 async 0/0/0
Jun  4 22:18:33 :: [    16150] return 0/0/0 async 0/0/0
Jun  4 22:18:38 :: [    16200] return 0/0/0 async 0/0/0
Jun  4 22:18:43 :: [    16250] return 0/0/0 async 0/0/0
char.cpp Sonitex rehberi:
Genişlet Daralt Kopyala
//EKLE :
#ifdef WJ_PREMIUM_PRIVATE_SHOP
#include "private_shop_manager.h"
#include "private_shop.h"
#include "private_shop_util.h"
#endif

//ARA :
    m_iSyncHackCount = 0;

//ALTINA EKLE :
#ifdef WJ_PREMIUM_PRIVATE_SHOP
    m_pPrivateShop = nullptr;
    m_pMyPrivateShop = nullptr;
    m_dwPrivateShopOwner = 0;
    m_bIsEditingPrivateShop = false;
    memset(&m_privateShopTable, 0, sizeof(TPrivateShop));

    m_bShopSearchMode = MODE_NONE;

    m_tLastPrivateShopModify        = 0;
    m_tLastPrivateShopWithdraw        = 0;
    m_tLastPrivateShopClose            = 0;
    m_tLastPrivateShopBuild            = 0;
    m_tLastPrivateShopBuy            = 0;
    m_tLastPrivateShopSearch        = 0;
    m_tLastPrivateShopStateChange    = 0;
#endif

//ARA :
    if (GetArena() != NULL)
    {
        GetArena()->OnDisconnect(GetPlayerID());
    }

//ÜSTÜNE EKLE :
#ifdef WJ_PREMIUM_PRIVATE_SHOP
    if (GetViewingPrivateShop())
    {
        GetViewingPrivateShop()->RemoveShopViewer(this);
        SetViewingPrivateShop(nullptr);
    }

    //    @note: DB does not get notified about characters disconnect when a player is going back to
    //            the select character window.     
    if (IsPrivateShopOwner() && strcmp(c_pszReason, "timed_event - SCMD_PHASE_SELECT") == 0)
    {
        // Update db
        BYTE bSubHeader = PRIVATE_SHOP_GD_SUBHEADER_LOGOUT;
        DWORD dwPID = GetPlayerID();

        db_clientdesc->DBPacketHeader(HEADER_GD_PRIVATE_SHOP, 0, sizeof(BYTE) + sizeof(DWORD));
        db_clientdesc->Packet(&bSubHeader, sizeof(BYTE));
        db_clientdesc->Packet(&dwPID, sizeof(DWORD));
    }
#endif

//ARA :
    if (GetExchange() || GetMyShop() || GetShopOwner() || IsOpenSafebox() || IsCubeOpen())
        return false;

//ALTINA EKLE :
#ifdef WJ_PREMIUM_PRIVATE_SHOP
    if (GetViewingPrivateShop() || IsEditingPrivateShop() || IsShopSearch())
        return false;
#endif

//EN SONA EKLE :
#ifdef WJ_PREMIUM_PRIVATE_SHOP
bool CHARACTER::BuildPrivateShop(const char* c_szTitle, DWORD dwPolyVnum, BYTE bTitleType, BYTE bPageCount, WORD wItemCount, TPrivateShopItem* pShopItemTable)
{
    if (!CanHandleItem())
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot use a personal shop now."));
        return false;
    }

    if (!CountSpecifyItem(50200) && !CountSpecifyItem(71221))
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot open a personal shop without a Bundle."));
        return false;
    }

    if ((dwPolyVnum > 30000 || bTitleType > 0) && !CountSpecifyItem(71221))
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot open a personal shop without a Bundle."));
        return false;
    }

    if (IsPrivateShopOwner())
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You have already opened your personal shop."));
        return false;
    }

    if (GetDungeon())
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot open a personal shop in a dungeon."));
        return false;
    }

    if (m_pkExchange)
        m_pkExchange->Cancel();

    quest::PC* pPC = quest::CQuestManager::instance().GetPCForce(GetPlayerID());
    if (pPC->IsRunning())
        return false;

    if (wItemCount == 0)
    {
        sys_err("Item count is equal to zero for player %d", GetPlayerID());
        return false;
    }

    if (CBanwordManager::instance().CheckString(c_szTitle, strlen(c_szTitle)))
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Please choose another title name for your personal shop."));
        return false;
    }

    if (strlen(c_szTitle) < TITLE_MIN_LEN)
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The entered name is too short."));
        return false;
    }

    std::vector<TPrivateShopItem> s_vec_shopItem;
    std::set<TItemPos> s_set_item;

    for (BYTE i = 0; i < wItemCount; ++i, ++pShopItemTable)
    {
        if (s_set_item.find(pShopItemTable->TPos) != s_set_item.end())
        {
            sys_err("Duplicated item in private shop detected! (name: %s)", GetName());
            return false;
        }

        const LPITEM pItem = GetItem(pShopItemTable->TPos);
        if (!pItem)
        {
            sys_err("Could not find an item in position: %d", pShopItemTable->TPos.cell);
            return false;
        }

        if (pItem->GetVnum() == 50200 || pItem->GetVnum() == 71221)
        {
            ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot put Bundles items in a personal shop when building it."));
            return false;
        }

        const TItemTable* pItemTable = pItem->GetProto();
        if (!pItemTable)
        {
            sys_err("Could not find an item table for an item at position: %d vnum: %d", pShopItemTable->TPos.cell, pItem->GetVnum());
            return false;
        }

        if (pItemTable && (IS_SET(pItemTable->dwAntiFlags, ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_MYSHOP)))
        {
            ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot sell Item-Shop items in a personal shop."));
            return false;
        }

        if (pItem->IsEquipped())
        {
            ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot sell equipped items in a personal shop."));
            return false;
        }

#ifdef WJ_SOULBINDING_SYSTEM
        if (pItem->IsBind() || pItem->IsUntilBind())
        {
            ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can't sell this item because is binded!"));
            return false;
        }
#endif

        if (pItem->isLocked())
        {
            ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot sell locked items in a personal shop."));
            return false;
        }

        if (pShopItemTable->TPrice.llGold < 0)
        {
            sys_err("Player %u is trying to build private shop with negative prices", GetPlayerID());
            return false;
        }

        pItem->Lock(true);//Darklovers_Fix_Offline_Shop

        s_set_item.insert(pShopItemTable->TPos);
        s_vec_shopItem.push_back(*pShopItemTable);
    }

    if (dwPolyVnum < 30000 || dwPolyVnum > 30008)
        dwPolyVnum = 30000;

    if (CPrivateShopManager::Instance().BuildPrivateShop(this, c_szTitle, dwPolyVnum, bTitleType, bPageCount, s_vec_shopItem))
    {
        {
            if (dwPolyVnum != 30000 || bTitleType != 0 || bPageCount == PRIVATE_SHOP_PAGE_MAX_NUM)
                RemoveSpecifyItem(71221);
            else
                RemoveSpecifyItem(50200);
        }
    }
    return true;
}

void CHARACTER::ClosePrivateShop()
{
    memset(&m_privateShopTable, 0, sizeof(m_privateShopTable));
    m_vec_privateShopItem.clear();

    ClosePrivateShopPanel();

    if (GetDesc())
    {
        TPacketGCPrivateShop mainPacket{};
        mainPacket.bHeader = HEADER_GC_PRIVATE_SHOP;
        mainPacket.wSize = sizeof(TPacketGCPrivateShop);
        mainPacket.bSubHeader = SUBHEADER_GC_PRIVATE_SHOP_CLOSE;

        GetDesc()->Packet(&mainPacket, sizeof(mainPacket));
    }

    ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Your personal shop has been closed."));
}

void CHARACTER::SetPrivateShopTable(const TPrivateShop& rPrivateShopTable)
{
    if (GetDesc())
    {
        TPacketGCPrivateShop mainPacket{};
        mainPacket.bHeader = HEADER_GC_PRIVATE_SHOP;
        mainPacket.wSize = sizeof(TPacketGCPrivateShop) + sizeof(TPacketGCPrivateShopLoad);
        mainPacket.bSubHeader = SUBHEADER_GC_PRIVATE_SHOP_LOAD;

        TPacketGCPrivateShopLoad subPacket{};
        strlcpy(subPacket.szTitle, rPrivateShopTable.szTitle, sizeof(subPacket.szTitle));
        subPacket.llGold = rPrivateShopTable.llGold;
        subPacket.dwCheque = rPrivateShopTable.dwCheque;
        subPacket.lX = rPrivateShopTable.lX;
        subPacket.lY = rPrivateShopTable.lY;
        subPacket.bChannel = rPrivateShopTable.bChannel;
        subPacket.bState = rPrivateShopTable.bState;
        subPacket.bPageCount = rPrivateShopTable.bPageCount;

        GetDesc()->BufferedPacket(&mainPacket, sizeof(TPacketGCPrivateShop));
        GetDesc()->Packet(&subPacket, sizeof(TPacketGCPrivateShopLoad));
    }

    m_privateShopTable = rPrivateShopTable;
}

void CHARACTER::OpenPrivateShopPanel()
{
    if (GetViewingPrivateShop())
        GetViewingPrivateShop()->RemoveShopViewer(this);

    SetEditingPrivateShop(true);

    if (GetDesc())
    {
        TPacketGCPrivateShop mainPacket{};
        mainPacket.bHeader = HEADER_GC_PRIVATE_SHOP;
        mainPacket.wSize = sizeof(TPacketGCPrivateShop);
        mainPacket.bSubHeader = SUBHEADER_GC_PRIVATE_SHOP_OPEN_PANEL;

        GetDesc()->Packet(&mainPacket, sizeof(mainPacket));
    }
}

void CHARACTER::ClosePrivateShopPanel(bool bSendClient /* = false */)
{
    if (!IsEditingPrivateShop())
        return;

    SetEditingPrivateShop(false);
    SetMyShopTime();

    if (bSendClient)
    {
        if (GetDesc())
        {
            TPacketGCPrivateShop mainPacket{};
            mainPacket.bHeader = HEADER_GC_PRIVATE_SHOP;
            mainPacket.wSize = sizeof(TPacketGCPrivateShop);
            mainPacket.bSubHeader = SUBHEADER_GC_PRIVATE_SHOP_CLOSE_PANEL;

            GetDesc()->Packet(&mainPacket, sizeof(mainPacket));
        }
    }
}

long long CHARACTER::GetPrivateShopTotalGold()
{
    long long llGold = GetPrivateShopTable()->llGold;

    for (const auto& rShopItem : m_vec_privateShopItem)
        llGold += rShopItem.TPrice.llGold;

    return llGold;
}

DWORD CHARACTER::GetPrivateShopTotalCheque()
{
    long long dwCheque = GetPrivateShopTable()->dwCheque;

    for (const auto& rShopItem : m_vec_privateShopItem)
        dwCheque += rShopItem.TPrice.dwCheque;

    return dwCheque;
}

void CHARACTER::SetPrivateShopItem(const TPlayerPrivateShopItem& c_rPrivateShopItem)
{
    if (GetDesc())
    {
        TPacketGCPrivateShop mainPacket{};
        mainPacket.bHeader = HEADER_GC_PRIVATE_SHOP;
        mainPacket.wSize = sizeof(TPacketGCPrivateShop) + sizeof(TPrivateShopItemData);
        mainPacket.bSubHeader = SUBHEADER_GC_PRIVATE_SHOP_SET_ITEM;

        TPrivateShopItemData subPacket{};
        CopyItemData(c_rPrivateShopItem, subPacket);

        GetDesc()->BufferedPacket(&mainPacket, sizeof(TPacketGCPrivateShop));
        GetDesc()->Packet(&subPacket, sizeof(TPrivateShopItemData));
    }

    m_vec_privateShopItem.push_back(c_rPrivateShopItem);
}

bool CHARACTER::RemovePrivateShopItem(WORD wPos)
{
    for (auto it = m_vec_privateShopItem.begin(); it != m_vec_privateShopItem.end(); ++it)
    {
        const TPlayerPrivateShopItem& r_shopItem = *it;
        if (r_shopItem.wPos == wPos)
        {
            TPacketGCPrivateShop mainPacket{};
            mainPacket.bHeader = HEADER_GC_PRIVATE_SHOP;
            mainPacket.wSize = sizeof(TPacketGCPrivateShop) + sizeof(WORD);
            mainPacket.bSubHeader = SUBHEADER_GC_PRIVATE_SHOP_REMOVE_MY_ITEM;

            GetDesc()->BufferedPacket(&mainPacket, sizeof(TPacketGCPrivateShop));
            GetDesc()->Packet(&wPos, sizeof(WORD));

            m_vec_privateShopItem.erase(it);
            return true;
        }
    }

    return false;
}

const TPlayerPrivateShopItem* CHARACTER::GetPrivateShopItem(WORD wPos)
{
    for (auto it = m_vec_privateShopItem.begin(); it != m_vec_privateShopItem.end(); ++it)
    {
        const TPlayerPrivateShopItem& rShopItem = *it;
        if (rShopItem.wPos == wPos)
            return &rShopItem;
    }
    return nullptr;
}

void CHARACTER::ChangePrivateShopItemPrice(WORD wPos, long long llGold, DWORD dwCheque)
{
    for (auto it = m_vec_privateShopItem.begin(); it != m_vec_privateShopItem.end(); ++it)
    {
        TPlayerPrivateShopItem& r_shopItem = *it;
        if (r_shopItem.wPos == wPos)
        {
            // Update prices of the item
            r_shopItem.TPrice.llGold = llGold;
            r_shopItem.TPrice.dwCheque = dwCheque;

            // Send information to client
            TPacketGCPrivateShop mainPacket{};
            mainPacket.bHeader = HEADER_GC_PRIVATE_SHOP;
            mainPacket.wSize = sizeof(TPacketGCPrivateShop) + sizeof(TPacketGCPrivateShopItemPriceChange);
            mainPacket.bSubHeader = SUBHEADER_GC_PRIVATE_SHOP_ITEM_PRICE_CHANGE;

            TPacketGCPrivateShopItemPriceChange subPacket{};
            subPacket.wPos = wPos;
            subPacket.TPrice.llGold = llGold;
            subPacket.TPrice.dwCheque = dwCheque;

            GetDesc()->BufferedPacket(&mainPacket, sizeof(TPacketGCPrivateShop));
            GetDesc()->Packet(&subPacket, sizeof(TPacketGCPrivateShopItemPriceChange));

            break;
        }
    }
}

void CHARACTER::ChangePrivateShopItemPos(WORD wPos, WORD wChangePos)
{
    for (auto it = m_vec_privateShopItem.begin(); it != m_vec_privateShopItem.end(); ++it)
    {
        TPlayerPrivateShopItem& r_shopItem = *it;
        if (r_shopItem.wPos == wPos)
        {
            // Update position of the item
            r_shopItem.wPos = wChangePos;

            // Send information to client
            TPacketGCPrivateShop mainPacket{};
            mainPacket.bHeader = HEADER_GC_PRIVATE_SHOP;
            mainPacket.wSize = sizeof(TPacketGCPrivateShop) + sizeof(TPacketGCPrivateShopItemMove);
            mainPacket.bSubHeader = SUBHEADER_GC_PRIVATE_SHOP_ITEM_MOVE;

            TPacketGCPrivateShopItemMove subPacket{};
            subPacket.wPos = wPos;
            subPacket.wChangePos = wChangePos;

            GetDesc()->BufferedPacket(&mainPacket, sizeof(TPacketGCPrivateShop));
            GetDesc()->Packet(&subPacket, sizeof(TPacketGCPrivateShopItemMove));

            break;
        }
    }
}

void CHARACTER::ChangePrivateShopTitle(const char* c_szTitle)
{
    strlcpy(m_privateShopTable.szTitle, c_szTitle, sizeof(m_privateShopTable.szTitle));

    if (GetDesc())
    {
        TPacketGCPrivateShop mainPacket{};
        mainPacket.bHeader = HEADER_GC_PRIVATE_SHOP;
        mainPacket.wSize = sizeof(TPacketGCPrivateShop) + sizeof(m_privateShopTable.szTitle);
        mainPacket.bSubHeader = SUBHEADER_GC_PRIVATE_SHOP_TITLE_CHANGE;

        GetDesc()->BufferedPacket(&mainPacket, sizeof(TPacketGCPrivateShop));
        GetDesc()->Packet(&m_privateShopTable.szTitle, sizeof(m_privateShopTable.szTitle));
    }
}

void CHARACTER::SaleUpdate(const TPlayerPrivateShopItem& c_rPrivateShopItem, const char* c_szCustomerName)
{
    const TPlayerPrivateShopItem* pShopItem = GetPrivateShopItem(c_rPrivateShopItem.wPos);
    if (pShopItem)
    {
        // Update the stash values at table
        GetPrivateShopTable()->llGold += c_rPrivateShopItem.TPrice.llGold;
        GetPrivateShopTable()->dwCheque += c_rPrivateShopItem.TPrice.dwCheque;

        // Remove the bought item
        RemovePrivateShopItem(c_rPrivateShopItem.wPos);

        // Send the balance update
        if (GetDesc())
        {
            // Send a notification to the player
            TItemTable* pItemTable = ITEM_MANAGER::Instance().GetTable(c_rPrivateShopItem.dwVnum);
            if (pItemTable)
            {
                char szMsg[256 + 1]{};

                int len = 0;
#ifdef WJ_PRIVATE_SHOP_CHEQUE
                {
                    len = snprintf(szMsg, sizeof(szMsg), LC_TEXT("You have sold x%d %s for %s Yangs and %s Wons."),
                        c_rPrivateShopItem.dwCount, pItemTable->szLocaleName,
                        format_number(c_rPrivateShopItem.TPrice.llGold).c_str(), format_number(c_rPrivateShopItem.TPrice.dwCheque).c_str());
                }
#else
                {
                    len = snprintf(szMsg, sizeof(szMsg), LC_TEXT("You have sold x%d %s for %s Yangs."),
                        c_rPrivateShopItem.dwCount, pItemTable->szLocaleName, format_number(c_rPrivateShopItem.TPrice.llGold).c_str());
                }
#endif
                TPacketGCWhisper packet{};

                packet.bHeader = HEADER_GC_WHISPER;
                packet.wSize = sizeof(TPacketGCWhisper) + len;
                packet.bType = EWhisperType::WHISPER_TYPE_SYSTEM;
                strlcpy(packet.szNameFrom, "Private Shop", sizeof(packet.szNameFrom));

                TEMP_BUFFER buf;

                buf.write(&packet, sizeof(packet));
                buf.write(szMsg, len);

                GetDesc()->Packet(buf.read_peek(), buf.size());
            }

            TPacketGCPrivateShop mainPacket{};
            mainPacket.bHeader = HEADER_GC_PRIVATE_SHOP;
            mainPacket.wSize = sizeof(TPacketGCPrivateShop) + sizeof(TPacketGCPrivateShopBalanceUpdate);
            mainPacket.bSubHeader = SUBHEADER_GC_PRIVATE_SHOP_BALANCE_UPDATE;

            TPacketGCPrivateShopBalanceUpdate subPacket{};
            subPacket.TPrice = c_rPrivateShopItem.TPrice;

            GetDesc()->BufferedPacket(&mainPacket, sizeof(TPacketGCPrivateShop));
            GetDesc()->Packet(&subPacket, sizeof(TPacketGCPrivateShopBalanceUpdate));
        }
    }
}

void CHARACTER::ItemExpireUpdate(WORD wPos)
{
    const TPlayerPrivateShopItem* pShopItem = GetPrivateShopItem(wPos);

    if (!pShopItem)
    {
        sys_err("Could not find item on pos %u for player %u", wPos, GetPlayerID());
        return;
    }

    // Send a notification to the player
    TItemTable* pItemTable = ITEM_MANAGER::Instance().GetTable(pShopItem->dwVnum);
    if (pItemTable)
    {
        char szMsg[128 + 1]{};

        int len = snprintf(szMsg, sizeof(szMsg), LC_TEXT("%s has been removed from the shop as the time has expired."),
            pItemTable->szLocaleName);

        TPacketGCWhisper packet{};

        packet.bHeader = HEADER_GC_WHISPER;
        packet.wSize = sizeof(TPacketGCWhisper) + len;
        packet.bType = EWhisperType::WHISPER_TYPE_SYSTEM;
        strlcpy(packet.szNameFrom, "Private Shop", sizeof(packet.szNameFrom));

        TEMP_BUFFER buf;

        buf.write(&packet, sizeof(packet));
        buf.write(szMsg, len);

        GetDesc()->Packet(buf.read_peek(), buf.size());
    }

    RemovePrivateShopItem(wPos);
}

void CHARACTER::SetPrivateShopState(BYTE bState, bool bIsMainPlayerPrivateShop)
{
    if (bIsMainPlayerPrivateShop)
        GetPrivateShopTable()->bState = bState;

    if (GetDesc())
    {
        TPacketGCPrivateShop mainPacket{};
        mainPacket.bHeader = HEADER_GC_PRIVATE_SHOP;
        mainPacket.wSize = sizeof(TPacketGCPrivateShop) + sizeof(TPacketGCPrivateStateUpdate);
        mainPacket.bSubHeader = SUBHEADER_GC_PRIVATE_SHOP_STATE_UPDATE;

        TPacketGCPrivateStateUpdate subPacket{};
        subPacket.bState = bState;
        subPacket.bIsMainPlayerPrivateShop = bIsMainPlayerPrivateShop;

        GetDesc()->BufferedPacket(&mainPacket, sizeof(TPacketGCPrivateShop));
        GetDesc()->Packet(&subPacket, sizeof(TPacketGCPrivateStateUpdate));
    }
}

void CHARACTER::WithdrawPrivateShop(long long llGold, DWORD dwCheque)
{
    if (llGold != GetPrivateShopTable()->llGold || dwCheque != GetPrivateShopTable()->dwCheque)
    {
        sys_err("Withdraw values mismatch gold: %lld | %lld cheque: %u | %u for player %u", llGold, GetPrivateShopTable()->llGold, dwCheque, GetPrivateShopTable()->dwCheque, GetPlayerID());
        return;

    }
    long long llCurrentGold = static_cast<long long>(GetGold());

#ifdef WJ_PRIVATE_SHOP_CHEQUE
    DWORD dwCurrentCheque = GetCheque();
#endif

    if ((llCurrentGold + GetPrivateShopTable()->llGold) >= GOLD_MAX)
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot collect the money, because you would then have more than 2 billion Yang."));
        return;
    }

#ifdef WJ_PRIVATE_SHOP_CHEQUE
    if ((dwCurrentCheque + GetPrivateShopTable()->dwCheque) > CHEQUE_MAX)
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot collect the money, because you would then have more than 999 Won."));
        return;
    }
#endif

    PointChange(POINT_GOLD, GetPrivateShopTable()->llGold);

#ifdef WJ_PRIVATE_SHOP_CHEQUE
    PointChange(POINT_CHEQUE, GetPrivateShopTable()->dwCheque);
#endif

    if (GetPrivateShopTable()->llGold && GetPrivateShopTable()->dwCheque <= 0)
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You have withdrawn %lld Yang from your personal shop earnings."), GetPrivateShopTable()->llGold);
#ifdef WJ_PRIVATE_SHOP_CHEQUE
    else if (GetPrivateShopTable()->dwCheque && GetPrivateShopTable()->llGold <= 0)
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You have withdrawn %u Won from your personal shop earnings."), GetPrivateShopTable()->dwCheque);
    else if(GetPrivateShopTable()->llGold && GetPrivateShopTable()->dwCheque)
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You have withdrawn %lld Yang and %u Won from your personal shop earnings."), GetPrivateShopTable()->llGold, GetPrivateShopTable()->dwCheque);
#endif

    sys_log(0, "%s PRIVATE_SHOP: WITHDRAW GOLD %lld CHEQUE %u", GetName(), GetPrivateShopTable()->llGold, GetPrivateShopTable()->dwCheque);

    char szHint[128 + 1] {};
    snprintf(szHint, sizeof(szHint), "Gold %lld Cheque %u", GetPrivateShopTable()->llGold, GetPrivateShopTable()->dwCheque);
    LogManager::Instance().CharLog(this, 0, "PRIVATE SHOP WITHDRAW", szHint);

    GetPrivateShopTable()->llGold = 0;
    GetPrivateShopTable()->dwCheque = 0;

    // Update the value on client-side
    if (GetDesc())
    {
        TPacketGCPrivateShop mainPacket{};
        mainPacket.bHeader = HEADER_GC_PRIVATE_SHOP;
        mainPacket.wSize = sizeof(TPacketGCPrivateShop);
        mainPacket.bSubHeader = SUBHEADER_GC_PRIVATE_SHOP_WITHDRAW;

        GetDesc()->Packet(&mainPacket, sizeof(TPacketGCPrivateShop));
    }

    // Update the value on db
    BYTE bSubHeader = PRIVATE_SHOP_GD_SUBHEADER_WITHDRAW;
    DWORD dwPID = GetPlayerID();
    db_clientdesc->DBPacketHeader(HEADER_GD_PRIVATE_SHOP, 0, sizeof(BYTE) + sizeof(DWORD));
    db_clientdesc->Packet(&bSubHeader, sizeof(BYTE));
    db_clientdesc->Packet(&dwPID, sizeof(DWORD));
}

void CHARACTER::OpenShopSearch(BYTE bMode)
{
    if (!CheckTradeWindows(this))
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot trade while another window is open."));
        return;
    }

    m_bShopSearchMode = bMode;

    if (GetDesc())
    {
        TPacketGCPrivateShop mainPacket{};
        mainPacket.bHeader = HEADER_GC_PRIVATE_SHOP;
        mainPacket.wSize = sizeof(TPacketGCPrivateShop);
        mainPacket.bSubHeader = (bMode == MODE_LOOKING ? SUBHEADER_GC_PRIVATE_SHOP_SEARCH_OPEN_LOOK_MODE : SUBHEADER_GC_PRIVATE_SHOP_SEARCH_OPEN_TRADE_MODE);

        GetDesc()->Packet(&mainPacket, sizeof(mainPacket));
    }
}

void CHARACTER::CloseShopSearch()
{
    m_bShopSearchMode = MODE_NONE;
}

bool CHARACTER::SetPremiumPrivateShopBonus(time_t tDuration)
{
    if (!GetDesc())
        return false;

    CAffect* pAffect = FindAffect(AFFECT_PREMIUM_PRIVATE_SHOP);
    if (pAffect)
    {
        tDuration = std::min<time_t>(tDuration + pAffect->lDuration, PRIVATE_SHOP_MAX_PREMIUM_TIME);

        // Return if player has reached limit moments ago
        if (PRIVATE_SHOP_MAX_PREMIUM_TIME - pAffect->lDuration < 60)
        {
            ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You have just recently reached maximum premium time for your personal shop. "));
            return false;
        }
    }

    // Old affect will be removed by AddAffect
    AddAffect(AFFECT_PREMIUM_PRIVATE_SHOP, POINT_NONE, 0, 0, tDuration, 0, true);

    m_aiPremiumTimes[PREMIUM_PRIVATE_SHOP] = tDuration + time(0);

    // Update db
    BYTE bSubHeader = PRIVATE_SHOP_GD_SUBHEADER_PREMIUM_TIME_UPDATE;

    TPacketGDPrivateShopPremiumTimeUpdate packet{};
    packet.dwAID = GetDesc()->GetAccountTable().id;
    packet.dwPID = GetPlayerID();
    packet.tPremiumTime = tDuration;

    db_clientdesc->DBPacketHeader(HEADER_GD_PRIVATE_SHOP, 0, sizeof(BYTE) + sizeof(TPacketGDPrivateShopPremiumTimeUpdate));
    db_clientdesc->Packet(&bSubHeader, sizeof(BYTE));
    db_clientdesc->Packet(&packet, sizeof(TPacketGDPrivateShopPremiumTimeUpdate));

    ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You have increased Premium Personal Shop duration."));

    // Warn the player about time limit
    if (tDuration == PRIVATE_SHOP_MAX_PREMIUM_TIME)
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You have reached maximum premium time for your personal shop. "));

    char szHint[128 + 1]{};
    snprintf(szHint, sizeof(szHint), "+%u", tDuration);
    LogManager::Instance().CharLog(this, 0, "PRIVATE SHOP PREMIUM TIME", szHint);

    return true;
}
#endif

char_item.cpp Sonitex Rehberi:
Genişlet Daralt Kopyala
//ARA :
                            case 50200:
                                if (g_bEnableBootaryCheck)
                                {
                                    if (IS_BOTARYABLE_ZONE(GetMapIndex()) == true)
                                    {
                                        __OpenPrivateShop();
                                    }
                                    else
                                    {
                                        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("개인 상점을 열 수 없는 지역입니다"));
                                    }
                                }
                                else
                                {
                                    __OpenPrivateShop();
                                }
                                break;

//DEĞİŞTİR :
                            case 50200:
                                if (g_bEnableBootaryCheck)
                                {
                                    if (IS_BOTARYABLE_ZONE(GetMapIndex()) == true)
                                    {
#ifdef WJ_PREMIUM_PRIVATE_SHOP
                                        if (IsPrivateShopOwner())
                                        {
                                            ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Close your current personal shop before opening a new one."));
                                            return false;
                                        }

                                        OpenPrivateShopPanel();
#else
                                        __OpenPrivateShop();
#endif
                                    }
                                    else
                                    {
                                        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("개인 상점을 열 수 없는 지역입니다"));
                                    }
                                }
                                else
                                {
#ifdef WJ_PREMIUM_PRIVATE_SHOP
                                    if (IsPrivateShopOwner())
                                    {
                                        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Close your current personal shop before opening a new one."));
                                        return false;
                                    }

                                    OpenPrivateShopPanel();
#else
                                    __OpenPrivateShop();
#endif
                                }
                                break;

#ifdef WJ_PREMIUM_PRIVATE_SHOP
                            case 71221:
                            {
                                if (IsPrivateShopOwner())
                                {
                                    ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Close your current personal shop before opening a new one."));
                                    return false;
                                }

                                OpenPrivateShopPanel();
                                ChatPacket(CHAT_TYPE_COMMAND, "SetPrivateShopPremiumBuild");
                            }
                            break;

                            case 60004:
                            {
                                OpenShopSearch(MODE_LOOKING);
                            }
                            break;

                            case 60005:
                            {
                                OpenShopSearch(MODE_TRADING);
                            }
                            break;
#endif

//ARA :
                            if (FindAffect(item->GetValue(0), aApplyInfo[item->GetValue(1)].bPointType))

//ÜSTÜNE EKLE :
#ifdef WJ_PREMIUM_PRIVATE_SHOP
                            if (item->GetValue(0) == AFFECT_PREMIUM_PRIVATE_SHOP)
                            {
                                if (SetPremiumPrivateShopBonus(item->GetValue(3)))
                                    item->SetCount(item->GetCount() - 1);
                                return true;
                            }
#endif

//ARA :
    sys_log(0, "%s: USE_ITEM %s (inven %d, cell: %d)", GetName(), item->GetName(), window_type, wCell);

//ALTINA EKLE :
#ifdef WJ_PREMIUM_PRIVATE_SHOP
    if (IsEditingPrivateShop())
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot use items while editing your personal shop."));
        return false;
    }
#endif

//ARA :
    if (!IsValidItemPosition(DestCell))
    {
        return false;
    }

//ALTINA EKLE :
#ifdef WJ_PREMIUM_PRIVATE_SHOP
    if (IsEditingPrivateShop())
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot move items while your personal shop window is open."));
        return false;
    }
#endif

//ARA :
    if (IsWarping())    return false;

//ALTINA EKLE :
#ifdef WJ_PREMIUM_PRIVATE_SHOP
    if (IsEditingPrivateShop() || IsShopSearch() || GetMyPrivateShop()) return false;
#endif

char.h Sonitex Rehberi:
Genişlet Daralt Kopyala
//EKLE :
#ifdef WJ_PREMIUM_PRIVATE_SHOP
#include "packet.h"
#endif

//ARA :
class CPetSystem;

//ALTINA EKLE :
#ifdef WJ_PREMIUM_PRIVATE_SHOP
class CPrivateShop;
#endif

//ARA :
#ifdef __PET_SYSTEM__
    public:
        CPetSystem*            GetPetSystem()                { return m_petSystem; }

    protected:
        CPetSystem*            m_petSystem;

    public:
#endif

//ALTINA EKLE :
#ifdef WJ_PREMIUM_PRIVATE_SHOP
    private:
        LPPRIVATE_SHOP        m_pPrivateShop;
        LPPRIVATE_SHOP        m_pMyPrivateShop;
        DWORD                m_dwPrivateShopOwner;
        TPrivateShop        m_privateShopTable;
        bool                m_bIsEditingPrivateShop;
        BYTE                m_bShopSearchMode;

        time_t                m_tLastPrivateShopModify;
        time_t                m_tLastPrivateShopWithdraw;
        time_t                m_tLastPrivateShopClose;
        time_t                m_tLastPrivateShopBuy;
        time_t                m_tLastPrivateShopSearch;
        time_t                m_tLastPrivateShopStateChange;
        time_t                m_tLastPrivateShopBuild;

        std::vector<TPlayerPrivateShopItem>        m_vec_privateShopItem;

    public:
        bool                BuildPrivateShop(const char* c_szTitle, DWORD dwPolyVnum, BYTE bTitleType, BYTE bPageCount, WORD wItemCount, TPrivateShopItem* pShopItemTable);
        void                ClosePrivateShop();

        void                SetViewingPrivateShop(LPPRIVATE_SHOP pShop) { m_pPrivateShop = pShop; }
        LPPRIVATE_SHOP        GetViewingPrivateShop() const { return m_pPrivateShop; }

        void                SetMyPrivateShop(LPPRIVATE_SHOP pShop) { m_pMyPrivateShop = pShop; }
        LPPRIVATE_SHOP        GetMyPrivateShop() const { return m_pMyPrivateShop; }

        void                SetPrivateShopOwner(DWORD dwPID) { m_dwPrivateShopOwner = dwPID; }
        DWORD                GetPrivateShopOwner() { return m_dwPrivateShopOwner; }

        void                SetPrivateShopTable(const TPrivateShop& rPrivateShopTable);
        TPrivateShop*        GetPrivateShopTable() { return &m_privateShopTable; }
        bool                IsPrivateShopOwner() { return m_privateShopTable.dwOwner != 0; }
        bool                CanModifyPrivateShop() { return m_privateShopTable.bState == STATE_MODIFY; }

        void                SetEditingPrivateShop(bool bEditingPrivateShop) { m_bIsEditingPrivateShop = bEditingPrivateShop; }
        bool                IsEditingPrivateShop() const { return m_bIsEditingPrivateShop; }
        void                OpenPrivateShopPanel();
        void                ClosePrivateShopPanel(bool bSendClient = false);

        void                OpenShopSearch(BYTE bMode);
        void                CloseShopSearch();
        bool                IsShopSearch() const { return m_bShopSearchMode != MODE_NONE; }
        BYTE                GetShopSearchMode() { return m_bShopSearchMode; }

        long long                        GetPrivateShopTotalGold();
        DWORD                            GetPrivateShopTotalCheque();

        void                            SetPrivateShopItem(const TPlayerPrivateShopItem& c_rPrivateShopItem);
        bool                            RemovePrivateShopItem(WORD wPos);
        const TPlayerPrivateShopItem*    GetPrivateShopItem(WORD wPos);
        WORD                            GetPrivateShopItemCount() { return m_vec_privateShopItem.size(); }

        void                            ChangePrivateShopItemPrice(WORD wPos, long long llGold, DWORD dwCheque);
        void                            ChangePrivateShopItemPos(WORD wPos, WORD wChangePos);
        void                            ChangePrivateShopTitle(const char* c_szTitle);
        void                            SaleUpdate(const TPlayerPrivateShopItem& c_rPrivateShopItem, const char* c_szCustomerName);
        void                            ItemExpireUpdate(WORD wPos);
        void                            SetPrivateShopState(BYTE bState, bool bIsMainPlayerPrivateShop);
        void                            WithdrawPrivateShop(long long llGold, DWORD dwCheque);

        bool                            SetPremiumPrivateShopBonus(time_t tDuration);

        int                                GetLastPrivateShopModifyTime() const { return m_tLastPrivateShopModify; }
        void                            SetLastPrivateShopModifyTime() { m_tLastPrivateShopModify = thecore_pulse(); }

        int                                GetLastPrivateShopWithdrawTime() const { return m_tLastPrivateShopWithdraw; }
        void                            SetLastPrivateShopWithdrawTime() { m_tLastPrivateShopWithdraw = thecore_pulse(); }

        int                                GetLastPrivateShopCloseTime() const { return m_tLastPrivateShopClose; }
        void                            SetLastPrivateShopCloseTime() { m_tLastPrivateShopClose = thecore_pulse(); }

        int                                GetLastPrivateShopBuildTime() const { return m_tLastPrivateShopBuild; }
        void                            SetLastPrivateShopBuildTime() { m_tLastPrivateShopBuild = thecore_pulse(); }

        int                                GetLastPrivateShopBuyTime() const { return m_tLastPrivateShopBuy; }
        void                            SetLastPrivateShopBuyTime() { m_tLastPrivateShopBuy = thecore_pulse(); }

        int                                GetLastPrivateShopSearchTime() const { return m_tLastPrivateShopSearch; }
        void                            SetLastPrivateShopSearchTime() { m_tLastPrivateShopSearch = thecore_pulse(); }

        int                                GetLastPrivateShopStateChangeTime() const { return m_tLastPrivateShopStateChange; }
        void                            SetLastPrivateShopStateChangeTime() { m_tLastPrivateShopStateChange = thecore_pulse(); }
#endif
desc_client.cpp:
Genişlet Daralt Kopyala
#ifdef WJ_PREMIUM_PRIVATE_SHOP
                                pck.dwPID = d->GetCharacter() ? d->GetCharacter()->GetPlayerID() : 0;
                                pck.dwHandle = d->GetHandle();
                                pck.bHasPrivateShop = (d->GetCharacter() && d->GetCharacter()->IsPrivateShopOwner()) ? true : false;
#endif
 
Son düzenleme:
Pazar kapandıktan sonra owner'ın IsPrivateShopOwner() kontrolü hâlâ true dönüyor. Yani; despawn işlemi game/db tarafında private shop owner flag'ini temizlemiyor. Char.cpp veya IsPrivateShopOwner flagının nerede set edildiğini gönderirsen biraz daha detaylı bakılabilir ben sadece gördüğüm kadarını söyledim fazlasıda olabilir .
 
Pazar kapandıktan sonra owner'ın IsPrivateShopOwner() kontrolü hâlâ true dönüyor. Yani; despawn işlemi game/db tarafında private shop owner flag'ini temizlemiyor. Char.cpp veya IsPrivateShopOwner flagının nerede set edildiğini gönderirsen biraz daha detaylı bakılabilir ben sadece gördüğüm kadarını söyledim fazlasıda olabilir .
İlgili olabilecek yerleri konuya eklemeye çalıştım.
 
private_shop_manager.cpp ve .h de paylaşır mısın
private_shop_manager.cpp:
Genişlet Daralt Kopyala
#include "stdafx.h"
#include "private_shop_manager.h"
#include "private_shop.h"
#include "private_shop_util.h"
#include "char.h"
#include "char_manager.h"
#include "desc_client.h"
#include "mob_manager.h"
#include "config.h"
#include "db.h"
#include "item_manager.h"
#include "item.h"
#include "utils.h"
#include "entity.h"
#include "sectree_manager.h"
#include "p2p.h"
#include "buffer_manager.h"
#include "desc_manager.h"
#include "p2p.h"
#include "DragonSoul.h"
#include "log.h"
#include <memory> // <-- unique_ptr için gerekli kütüphane eklendi

void CPrivateShopManager::Destroy()
{
    m_map_privateShop.clear();
}

LPPRIVATE_SHOP CPrivateShopManager::CreatePrivateShop(DWORD dwPID)
{
    if (GetPrivateShop(dwPID))
        return nullptr;

    // C++11 Uyarlaması Yapıldı
    std::unique_ptr<CPrivateShop> upPrivateShop = std::unique_ptr<CPrivateShop>(new CPrivateShop());
    LPPRIVATE_SHOP pPrivateShop = upPrivateShop.get();

    DWORD dwVID = AllocVID();
    upPrivateShop->SetVID(dwVID);

    m_map_privateShop.emplace(dwPID, std::move(upPrivateShop));
    m_map_privateShopVID.emplace(dwVID, pPrivateShop);

    return pPrivateShop;
}

LPPRIVATE_SHOP CPrivateShopManager::GetPrivateShop(DWORD dwPID)
{
    auto it = m_map_privateShop.find(dwPID);
    if (it == m_map_privateShop.end())
        return nullptr;

    return it->second.get();
}

LPPRIVATE_SHOP CPrivateShopManager::GetPrivateShopByOwnerName(const char* c_szOwnerName)
{
    for (auto it = m_map_privateShop.begin(); it != m_map_privateShop.end(); ++it)
    {
        LPPRIVATE_SHOP pPrivateShop = it->second.get();

        if (pPrivateShop->GetOwnerName().compare(c_szOwnerName) == 0)
            return pPrivateShop;
    }

    return nullptr;
}

LPPRIVATE_SHOP CPrivateShopManager::GetPrivateShopByVID(DWORD dwVID)
{
    auto it = m_map_privateShopVID.find(dwVID);
    if (it == m_map_privateShopVID.end())
        return nullptr;

    return it->second;
}

bool CPrivateShopManager::DeletePrivateShop(DWORD dwPID)
{
    auto it = m_map_privateShop.find(dwPID);
    if (it == m_map_privateShop.end())
        return false;

    DWORD dwVID = it->second->GetVID();

    m_map_privateShopVID.erase(dwVID);
    m_map_privateShop.erase(it);
    return true;
}

bool CPrivateShopManager::BuildPrivateShop(LPCHARACTER pShopOwner, const char* c_szTitle, DWORD dwPolyVnum, BYTE bTitleType, BYTE bPageCount, const std::vector<TPrivateShopItem>& c_vec_shopItem)
{
    const CMob* pMobTable = CMobManager::Instance().Get(dwPolyVnum);
    if (!pMobTable)
    {
        sys_err("Cannot find mob table for vnum %u", dwPolyVnum);
        return false;
    }

    LPPRIVATE_SHOP pPrivateShop = CreatePrivateShop(pShopOwner->GetPlayerID());
    if (!pPrivateShop)
    {
        sys_err("Cannot create a private shop instance for player %s %u", pShopOwner->GetName(), pShopOwner->GetPlayerID());
        return false;
    }

    std::vector<TPlayerPrivateShopItem> vec_privateShopItem;
    for (const auto& c_rShopItem : c_vec_shopItem)
    {
        LPITEM pItem = pShopOwner->GetItem(c_rShopItem.TPos);

        TPlayerPrivateShopItem t{};

        CopyItemData(pItem, t);

        t.TPrice.llGold = c_rShopItem.TPrice.llGold;
#ifdef WJ_PRIVATE_SHOP_CHEQUE
        t.TPrice.dwCheque = c_rShopItem.TPrice.dwCheque;
#endif
        t.wPos = c_rShopItem.wDisplayPos;
        t.tCheckin = time(0);

        vec_privateShopItem.push_back(t);
    }

    std::string strTitle(c_szTitle);

    pPrivateShop->SetID(pShopOwner->GetPlayerID());
    pPrivateShop->SetVnum(dwPolyVnum);
    pPrivateShop->SetOwnerName(pShopOwner->GetName());
    pPrivateShop->SetTitle(c_szTitle);
    pPrivateShop->SetTitleType(bTitleType);
    pPrivateShop->SetState(STATE_OPEN);
    pPrivateShop->SetPageCount(bPageCount);

    if (!pPrivateShop->Initialize(vec_privateShopItem))
    {
        sys_err("Cannot initialize items to private shop");
        DeletePrivateShop(pShopOwner->GetPlayerID());

        return false;
    }

    const auto& itemContainer = pPrivateShop->GetItemContainer();
    for (const auto& kv : itemContainer)
        ITEM_MANAGER::Instance().FlushDelayedSave(kv.second);

    BYTE bSubHeader = PRIVATE_SHOP_GD_SUBHEADER_CREATE;
    WORD wCount = vec_privateShopItem.size();

    TPrivateShop t{};

    t.dwOwner = pShopOwner->GetPlayerID();
    strlcpy(t.szTitle, c_szTitle, sizeof(t.szTitle));
    strlcpy(t.szOwnerName, pShopOwner->GetName(), sizeof(t.szOwnerName));
    t.dwVnum = dwPolyVnum;
    t.bTitleType = bTitleType;
    t.lMapIndex = pShopOwner->GetMapIndex();
    t.lX = pShopOwner->GetX();
    t.lY = pShopOwner->GetY();
    t.bChannel = g_bChannel;
    t.wPort = mother_port;
    t.bState = STATE_OPEN;
    t.llGold = 0;
#ifdef WJ_PRIVATE_SHOP_CHEQUE
    t.dwCheque = 0;
#endif
    t.bPageCount = bPageCount;
    t.tPremiumTime = pShopOwner->GetPremiumRemainSeconds(PREMIUM_PRIVATE_SHOP) + time(0);

    db_clientdesc->DBPacketHeader(HEADER_GD_PRIVATE_SHOP, pShopOwner->GetDesc()->GetHandle(), sizeof(BYTE) + sizeof(TPrivateShop) + sizeof(WORD) + sizeof(TPlayerPrivateShopItem) * wCount);
    db_clientdesc->Packet(&bSubHeader, sizeof(BYTE));
    db_clientdesc->Packet(&t, sizeof(TPrivateShop));
    db_clientdesc->Packet(&wCount, sizeof(WORD));
    db_clientdesc->Packet(&vec_privateShopItem[0], sizeof(TPlayerPrivateShopItem) * wCount);

    return true;
}

void CPrivateShopManager::BuildPrivateShopResult(DWORD dwPID, TPrivateShop* pPrivateShopTable, bool bSuccess)
{
    LPPRIVATE_SHOP pPrivateShop = GetPrivateShop(dwPID);
    if (!pPrivateShop)
    {
        sys_err("Cannot find private shop with id %u", dwPID);
        return;
    }

    LPCHARACTER pOwner = CHARACTER_MANAGER::Instance().FindByPID(dwPID);
    if (!pOwner)
    {
        sys_err("Cannot find private shop owner with id %u", dwPID);
        return;
    }

    pOwner->ClosePrivateShopPanel(true);

    const auto& map_privateShopItem = pPrivateShop->GetItemContainer();
    for (const auto& kv : map_privateShopItem)
    {
        WORD wPos = kv.first;
        LPITEM pItem = kv.second;

        if (bSuccess)
        {
            pItem->SetSkipSave(true);

            pItem->Lock(false);//Darklovers_Fix_Offline_Shop

            pItem->RemoveFromCharacter();
            pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, pItem->GetCell(), 255);

            pItem->SetCell(nullptr, wPos);
            pItem->BindPrivateShop(pPrivateShop);

            TPlayerPrivateShopItem t{};
            CopyItemData(pItem, t);

            pOwner->SetPrivateShopItem(t);

            char szHint[128 + 1]{};
            snprintf(szHint, sizeof(szHint), "%s x%u pos %u gold %lld", pItem->GetName(), pItem->GetCount(), t.wPos, t.TPrice.llGold);
            LogManager::Instance().ItemLog(pOwner, pItem, "PRIVATE SHOP BUILD CHECKIN", szHint);
        }
        else
        {
            pItem->BindPrivateShop(nullptr);
            pItem->SetCheckinTime(0);
            pItem->SetGoldPrice(0);
#ifdef WJ_PRIVATE_SHOP_CHEQUE
            pItem->SetChequePrice(0);
#endif

            pItem->Lock(false);//Darklovers_Fix_Offline_Shop
        }
    }

    if (!bSuccess)
    {
        DeletePrivateShop(dwPID);
        pOwner->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot build a personal shop at this moment. "));

        sys_err("Private shop building process stopped for player %u", dwPID);
        return;
    }

    pPrivateShop->Show(pPrivateShopTable->lX, pPrivateShopTable->lY, 0, pPrivateShopTable->lMapIndex);
    pOwner->SetPrivateShopTable(*pPrivateShopTable);

    LogManager::Instance().CharLog(pOwner, 0, "PRIVATE SHOP BUILT", "");

    sys_log(0, "%s PRIVATE_SHOP: SUCCESS Shop entity created", pPrivateShopTable->szOwnerName);
}

void CPrivateShopManager::ClosePrivateShop(LPCHARACTER pShopOwner)
{
    DWORD dwPID = pShopOwner->GetPlayerID();

    LPPRIVATE_SHOP pPrivateShop = GetPrivateShop(dwPID);
    if (!pPrivateShop)
    {
        pShopOwner->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You are too far away from your personal shop."));
        return;
    }

    // Cancel if the player is not near his shop character
    long lShopMapIndex = pPrivateShop->GetMapIndex();
    if (pShopOwner->GetMapIndex() != lShopMapIndex)
    {
        pShopOwner->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot close a personal shop from a different location."));
        return;
    }

    if (DISTANCE_APPROX(pPrivateShop->GetX() - pShopOwner->GetX(), pPrivateShop->GetY() - pShopOwner->GetY()) > 3000)
    {
        pShopOwner->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You are too far away from your personal shop."));
        return;
    }

    pPrivateShop->SetClosing(true);
    if (pPrivateShop->TransferItems(pShopOwner))
    {
        // Close the window at customer's client
        pPrivateShop->CleanShopViewers();

        BYTE bSubHeader = PRIVATE_SHOP_GD_SUBHEADER_DELETE;

        db_clientdesc->DBPacketHeader(HEADER_GD_PRIVATE_SHOP, 0, sizeof(BYTE) + sizeof(DWORD));
        db_clientdesc->Packet(&bSubHeader, sizeof(BYTE));
        db_clientdesc->Packet(&dwPID, sizeof(DWORD));

        DeletePrivateShop(dwPID);

        pShopOwner->ClosePrivateShop();

        sys_log(0, "%s PRIVATE_SHOP: SUCCESS Shop entity closed", pShopOwner->GetName());
        LogManager::Instance().CharLog(pShopOwner, 0, "PRIVATE SHOP CLOSED", "");
    }
    else
    {
        sys_err("Failed to transfer items back to owner %u", pShopOwner->GetPlayerID());
        pPrivateShop->SetClosing(false);
    }
}

void CPrivateShopManager::SpawnPrivateShop(TPrivateShop* pPrivateShopTable, const std::vector<TPlayerPrivateShopItem>& c_vec_shopItem)
{
    const CMob* pMobTable = CMobManager::Instance().Get(pPrivateShopTable->dwVnum);
    if (!pMobTable)
    {
        sys_err("Cannot find mob table for vnum %u", pPrivateShopTable->dwVnum);
        return;
    }

    if (GetPrivateShop(pPrivateShopTable->dwOwner))
        DeletePrivateShop(pPrivateShopTable->dwOwner);

    LPPRIVATE_SHOP pPrivateShop = CreatePrivateShop(pPrivateShopTable->dwOwner);
    if (!pPrivateShop)
    {
        sys_err("Cannot create a private shop instance for player %s %u", pPrivateShopTable->szOwnerName, pPrivateShopTable->dwOwner);
        return;
    }

    LPSECTREE pSectree = SECTREE_MANAGER::instance().Get(pPrivateShopTable->lMapIndex, pPrivateShopTable->lX, pPrivateShopTable->lY);

    if (!pSectree)
    {
        sys_err("Cannot find sectree %dx%d mapindex %d for private shop %s %d", pPrivateShopTable->lY, pPrivateShopTable->lY, pPrivateShopTable->lMapIndex,
            pPrivateShopTable->szOwnerName, pPrivateShopTable->dwOwner);
        return;
    }

    if (pPrivateShopTable->bState < STATE_OPEN)
    {
        sys_err("Cannot spawn a private shop %u with state %u", pPrivateShopTable->dwOwner, pPrivateShopTable->bState);
        return;
    }

    // Bind data to the private shop
    pPrivateShop->SetID(pPrivateShopTable->dwOwner);
    pPrivateShop->SetVnum(pPrivateShopTable->dwVnum);
    pPrivateShop->SetOwnerName(pPrivateShopTable->szOwnerName);
    pPrivateShop->SetTitle(pPrivateShopTable->szTitle);
    pPrivateShop->SetTitleType(pPrivateShopTable->bTitleType);
    pPrivateShop->SetState(pPrivateShopTable->bState);
    pPrivateShop->SetPageCount(pPrivateShopTable->bPageCount);

    // Create items and transfer them to the private shop
    if (!pPrivateShop->Initialize(c_vec_shopItem, true))
    {
        sys_err("Cannot initialize items to private shop");
        DespawnPrivateShop(pPrivateShopTable->dwOwner);

        sys_log(0, "%s PRIVATE_SHOP: FAILURE Shop entity not spawned", pPrivateShopTable->szOwnerName);
        return;
    }

    pPrivateShop->Show(pPrivateShopTable->lX, pPrivateShopTable->lY, 0, pPrivateShopTable->lMapIndex);

    sys_log(0, "%s PRIVATE_SHOP: SUCCESS Shop entity spawned", pPrivateShopTable->szOwnerName);

    LogManager::Instance().CharLog(pPrivateShopTable->dwOwner, pPrivateShopTable->lX, pPrivateShopTable->lY, 0, "PRIVATE SHOP SPAWN", "", "");
}

void CPrivateShopManager::DespawnPrivateShop(DWORD dwPID)
{
    BYTE bSubHeader = PRIVATE_SHOP_GD_SUBHEADER_DESPAWN;
    DWORD dwOwner = dwPID;

    db_clientdesc->DBPacketHeader(HEADER_GD_PRIVATE_SHOP, 0, sizeof(BYTE) + sizeof(DWORD));
    db_clientdesc->Packet(&bSubHeader, sizeof(BYTE));
    db_clientdesc->Packet(&dwOwner, sizeof(DWORD));

    LPPRIVATE_SHOP pPrivateShop = GetPrivateShop(dwPID);
    if (!pPrivateShop)
    {
        sys_err("Cannot find private shop with id %u", dwPID);
        return;
    }

    sys_log(0, "%s PRIVATE_SHOP: Shop entity despawned", pPrivateShop->GetOwnerName().c_str());
    DeletePrivateShop(dwPID);
}

bool CPrivateShopManager::StopShopping(LPCHARACTER pShopViewer)
{
    LPPRIVATE_SHOP pPrivateShop = pShopViewer->GetViewingPrivateShop();
    if (!pPrivateShop)
        return false;

    pPrivateShop->RemoveShopViewer(pShopViewer);
    pShopViewer->SetMyShopTime();

    return true;
}

void CPrivateShopManager::ItemCheckin(LPCHARACTER pOwner, const TPlayerPrivateShopItem* c_pShopItem)
{
    if (db_clientdesc->GetSocket() == INVALID_SOCKET)
        return;

    LPITEM pItem = ITEM_MANAGER::Instance().Find(c_pShopItem->dwID);
    if (!pItem)
    {
        sys_err("Cannot checkin item %u vnum %u for private shop %u (item not found)", c_pShopItem->dwID, c_pShopItem->dwVnum, pOwner->GetPlayerID());
        return;
    }

    if (!pItem->GetOwner())
    {
        sys_err("Cannot checkin item %u vnum %u for private shop %u (owner not found)", c_pShopItem->dwID, c_pShopItem->dwVnum, pOwner->GetPlayerID());
        return;
    }

    if (pItem->GetOwner() != pOwner)
    {
        sys_err("Cannot checkin item %u vnum %u for private shop %u (owner not equal to private shop owner)", c_pShopItem->dwID, c_pShopItem->dwVnum, pOwner->GetPlayerID());
        return;
    }

    pOwner->SetPrivateShopItem(*c_pShopItem);

    // Send check-in update back to db
    BYTE bSubHeader = PRIVATE_SHOP_GD_SUBHEADER_ITEM_CHECKIN_UPDATE;

    db_clientdesc->DBPacketHeader(HEADER_GD_PRIVATE_SHOP, pOwner->GetDesc()->GetHandle(), sizeof(BYTE) + sizeof(TPlayerPrivateShopItem));
    db_clientdesc->Packet(&bSubHeader, sizeof(BYTE));
    db_clientdesc->Packet(c_pShopItem, sizeof(TPlayerPrivateShopItem));

    char szHint[128 + 1]{};
    snprintf(szHint, sizeof(szHint), "%s x%u pos %u gold %lld",
        pItem->GetName(), pItem->GetCount(), c_pShopItem->wPos, c_pShopItem->TPrice.llGold);
    LogManager::Instance().ItemLog(pItem->GetOwner(), pItem, "PRIVATE SHOP CHECKIN", szHint);

    // Do not save the removal of item, will be done later on
    pItem->SetSkipSave(true);
    ITEM_MANAGER::Instance().RemoveItem(pItem);
}

void CPrivateShopManager::ItemCheckout(LPCHARACTER pOwner, WORD wSrcPos, TItemPos TDstPos)
{
    if (db_clientdesc->GetSocket() == INVALID_SOCKET)
        return;

    const TPlayerPrivateShopItem* c_pShopItem = pOwner->GetPrivateShopItem(wSrcPos);

    if (!c_pShopItem)
    {
        sys_err("cannot find private shop item at pos %u player %u", wSrcPos, pOwner->GetPlayerID());
        return;
    }

    LPITEM pItem = ITEM_MANAGER::Instance().Find(c_pShopItem->dwID);

    if (!pItem)
    {
        pItem = ITEM_MANAGER::Instance().CreateItem(c_pShopItem->dwVnum, c_pShopItem->dwCount, c_pShopItem->dwID);
        if (!pItem)
        {
            sys_err("cannot create item by vnum %u (id %u)", c_pShopItem->dwVnum, c_pShopItem->dwID);
            return;
        }

        pItem->OnAfterCreatedItem();
        CopyItemData(*c_pShopItem, pItem);
    }

    // Necessary to avoid AddToCharacter failure
    pItem->SetCell(nullptr, 0);

    // Try to move the item to the owner
    if (!pItem->AddToCharacter(pOwner, TItemPos(TDstPos.window_type, TDstPos.cell)))
    {
        sys_err("Cannot checkout item %u vnum %u from private shop %u", c_pShopItem->dwID, c_pShopItem->dwVnum, pOwner->GetPlayerID());

        // If item had no private shop bound it was re-created and can be removed
        if (!pItem->GetPrivateShop())
            M2_DESTROY_ITEM(pItem);
        else
            pItem->SetCell(nullptr, c_pShopItem->wPos); // Revert the cell back :)

        return;
    }

    // Item was successfully transfered to owner, reset private shop values
    pItem->BindPrivateShop(nullptr);
    pItem->SetGoldPrice(0);
#ifdef WJ_PRIVATE_SHOP_CHEQUE
    pItem->SetChequePrice(0);
#endif

    // Enable saving of the item
    pItem->SetSkipSave(false);

    // Remove the private shop item
    pOwner->RemovePrivateShopItem(wSrcPos);

    // Send check-out update back to db
    BYTE bSubHeader = PRIVATE_SHOP_GD_SUBHEADER_ITEM_CHECKOUT_UPDATE;

    TPlayerItem TItem {};
    CopyItemData(pItem, TItem);

    db_clientdesc->DBPacketHeader(HEADER_GD_PRIVATE_SHOP, pOwner->GetDesc()->GetHandle(), sizeof(BYTE) + sizeof(WORD) + sizeof(TPlayerItem));
    db_clientdesc->Packet(&bSubHeader, sizeof(BYTE));
    db_clientdesc->Packet(&wSrcPos, sizeof(WORD));
    db_clientdesc->Packet(&TItem, sizeof(TPlayerItem));

    char szHint[128 + 1]{};
    snprintf(szHint, sizeof(szHint), "%s x%u", pItem->GetName(), pItem->GetCount());
    LogManager::Instance().ItemLog(pItem->GetOwner(), pItem, "PRIVATE SHOP CHECKOUT", szHint);
}

bool CPrivateShopManager::ItemTransaction(LPCHARACTER pCustomer, TPlayerPrivateShopItem* c_pShopItem)
{
    if (db_clientdesc->GetSocket() == INVALID_SOCKET)
        return false;

    if (!c_pShopItem->dwOwner)
        return false;

    LPPRIVATE_SHOP pPrivateShop = GetPrivateShop(c_pShopItem->dwOwner);

    // Check if the item already exists, if not create it
    LPITEM pItem = ITEM_MANAGER::Instance().Find(c_pShopItem->dwID);

    if (pPrivateShop && !pItem)
        sys_err("No item data found for item %u vnum %u on private shop %u", c_pShopItem->dwID, c_pShopItem->dwVnum, c_pShopItem->dwOwner);

    bool bNewItem = false;
    if (!pItem)
    {
        pItem = ITEM_MANAGER::Instance().CreateItem(c_pShopItem->dwVnum, c_pShopItem->dwCount, c_pShopItem->dwID);
        if (!pItem)
        {
            sys_err("Cannot create item %u vnum %u", c_pShopItem->dwID, c_pShopItem->dwVnum);

            SendItemTransactionFailedResult(c_pShopItem->dwOwner, c_pShopItem->wPos);
            return false;
        }

        CopyItemData(*c_pShopItem, pItem);
        bNewItem = true;
    }

    // Check if there is enough space for the item
    int iPos = GetEmptyInventory(pCustomer, pItem);

    if (iPos < 0)
    {
        sys_err("Cannot find empty cell for item %u vnum %u", c_pShopItem->dwID, c_pShopItem->dwVnum);

        pCustomer->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You don't have enough space in your inventory."));
        SendItemTransactionFailedResult(c_pShopItem->dwOwner, c_pShopItem->wPos);

        if (bNewItem)
            M2_DESTROY_ITEM(pItem);

        return false;
    }

    // Was already checked on db?
    if (pCustomer->GetGold() < c_pShopItem->TPrice.llGold)
    {
        sys_log(0, "PRIVATE_SHOP: Insufficient gold at customer %s to buy item %u vnum %u", pCustomer->GetName(), c_pShopItem->dwID, c_pShopItem->dwVnum);

        pCustomer->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You don't have enough Yang."));
        SendItemTransactionFailedResult(c_pShopItem->dwOwner, c_pShopItem->wPos);

        if (bNewItem)
            M2_DESTROY_ITEM(pItem);

        return false;
    }

#ifdef WJ_PRIVATE_SHOP_CHEQUE
    if (static_cast<DWORD>(pCustomer->GetCheque()) < c_pShopItem->TPrice.dwCheque)
    {
        sys_log(0, "PRIVATE_SHOP: Insufficient cheque at customer %s to buy item %u vnum %u", pCustomer->GetName(), c_pShopItem->dwID, c_pShopItem->dwVnum);

        pCustomer->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You don't have enough Won."));
        SendItemTransactionFailedResult(c_pShopItem->dwOwner, c_pShopItem->wPos);
        return false;
    }
#endif

    // Bind data to the item
    pItem->SetSkipSave(true);
    pItem->BindPrivateShop(nullptr); // Break the private shop connection if the item was taken directly from shop (not p2p)

    // Remove private shop data
    pItem->SetGoldPrice(0);
#ifdef WJ_PRIVATE_SHOP_CHEQUE
    pItem->SetChequePrice(0);
#endif
    pItem->SetCheckinTime(0);

    // Reset item's ownership and cell
    pItem->SetCell(nullptr, 0);

    // Enable saving of the item
    pItem->SetSkipSave(false);

    BYTE bWindow = pItem->GetType() == ITEM_DS ? DRAGON_SOUL_INVENTORY : INVENTORY;
    if (!pItem->AddToCharacter(pCustomer, TItemPos(bWindow, iPos)))
    {
        // Bind private shop to the item if it exists on this core
        if (pPrivateShop)
        {
            CopyItemData(*c_pShopItem, pItem);
            pItem->BindPrivateShop(pPrivateShop);
            pItem->SetSkipSave(true);
        }
        else
        {
            M2_DESTROY_ITEM(pItem);
        }

        sys_log(0, "PRIVATE_SHOP: Failed to add item %u vnum %u to customer %s", c_pShopItem->dwID, c_pShopItem->dwVnum, pCustomer->GetName());
        SendItemTransactionFailedResult(c_pShopItem->dwOwner, c_pShopItem->wPos);
        return false;
    }

    // Remove item from the shop before resetting owner/position (if the shop is in another core, request from db will be sent)
    if (pPrivateShop)
        pPrivateShop->RemoveItem(c_pShopItem->wPos);

    pCustomer->PointChange(POINT_GOLD, -c_pShopItem->TPrice.llGold);

#ifdef WJ_PRIVATE_SHOP_CHEQUE
    int iChequePrice = c_pShopItem->TPrice.dwCheque;
    pCustomer->PointChange(POINT_CHEQUE, -iChequePrice);
#endif

    ITEM_MANAGER::Instance().SaveSingleItem(pItem);

    if (pItem->GetCount() > 1)
        pCustomer->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You have bought x%d %s."), pItem->GetCount(), pItem->GetName());
    else
        pCustomer->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You have bought %s."), pItem->GetName());

    sys_log(0, "PRIVATE_SHOP: SUCCESS Item transaction for customer %s item %u %u from shop %u", pCustomer->GetName(), c_pShopItem->dwID, c_pShopItem->dwVnum, c_pShopItem->dwOwner);

    // Send result back to db
    SendItemTransaction(c_pShopItem, pCustomer);

    char szHint[128 + 1]{};
    snprintf(szHint, sizeof(szHint), "%s x%u (Private Shop %u)", pItem->GetName(), pItem->GetCount(), c_pShopItem->dwOwner);
    LogManager::Instance().ItemLog(pItem->GetOwner(), pItem, "PRIVATE SHOP ITEM TRANSACTION", szHint);

    return true;
}

void CPrivateShopManager::SendItemTransaction(const TPlayerPrivateShopItem* c_pShopItem /* = nullptr */, LPCHARACTER pCustomer /* = nullptr */)
{
    BYTE bSubHeader = PRIVATE_SHOP_GD_SUBHEADER_BUY;

    TPacketGDPrivateShopBuy subPacket{};

    std::memcpy(&subPacket.TItem, c_pShopItem, sizeof(subPacket.TItem));
    strlcpy(subPacket.szCustomerName, pCustomer->GetName(), sizeof(subPacket.szCustomerName));
    subPacket.dwCustomer = pCustomer->GetPlayerID();

    db_clientdesc->DBPacketHeader(HEADER_GD_PRIVATE_SHOP, 0, sizeof(BYTE) + sizeof(TPacketGDPrivateShopBuy));
    db_clientdesc->Packet(&bSubHeader, sizeof(BYTE));
    db_clientdesc->Packet(&subPacket, sizeof(TPacketGDPrivateShopBuy));
}

void CPrivateShopManager::SendItemTransactionFailedResult(DWORD dwShopID, WORD wPos)
{
    BYTE bSubHeader = PRIVATE_SHOP_GD_SUBHEADER_FAILED_BUY;

    TPacketGDPrivateShopFailedBuy subPacket{};

    subPacket.dwShopID = dwShopID;
    subPacket.wPos = wPos;

    db_clientdesc->DBPacketHeader(HEADER_GD_PRIVATE_SHOP, 0, sizeof(BYTE) + sizeof(TPacketGDPrivateShopFailedBuy));
    db_clientdesc->Packet(&bSubHeader, sizeof(BYTE));
    db_clientdesc->Packet(&subPacket, sizeof(TPacketGDPrivateShopFailedBuy));
}

void CPrivateShopManager::SendItemTransfer(const TPlayerItem* c_pItem)
{
    BYTE bSubHeader = PRIVATE_SHOP_GD_SUBHEADER_ITEM_TRANSFER;

    db_clientdesc->DBPacketHeader(HEADER_GD_PRIVATE_SHOP, 0, sizeof(BYTE) + sizeof(TPlayerItem));
    db_clientdesc->Packet(&bSubHeader, sizeof(BYTE));
    db_clientdesc->Packet(c_pItem, sizeof(TPlayerItem));
}

void CPrivateShopManager::SendItemExpire(LPITEM pItem)
{
    LPPRIVATE_SHOP pPrivateShop = pItem->GetPrivateShop();

    BYTE bSubHeader = PRIVATE_SHOP_GD_SUBHEADER_ITEM_EXPIRE;

    TPacketGDPrivateShopItemExpire subPacket{};
    subPacket.dwShopID = pPrivateShop->GetID();
    subPacket.wPos = pItem->GetCell();

    db_clientdesc->DBPacketHeader(HEADER_GD_PRIVATE_SHOP, 0, sizeof(BYTE) + sizeof(TPacketGDPrivateShopItemExpire));
    db_clientdesc->Packet(&bSubHeader, sizeof(BYTE));
    db_clientdesc->Packet(&subPacket, sizeof(TPacketGDPrivateShopItemExpire));

    pPrivateShop->RemoveItem(pItem->GetCell());
}

void CPrivateShopManager::AddSearchItem(LPITEM pItem)
{
    BYTE bItemType = pItem->GetType();
    BYTE bItemSubType = pItem->GetSubType();

    TItemList& itemList = m_map_searchItem[bItemType][bItemSubType];
    itemList.emplace(pItem);
}

void CPrivateShopManager::RemoveSearchItem(LPITEM pItem)
{
    if (!pItem)
        return;

    BYTE bItemType = pItem->GetType();
    BYTE bItemSubType = pItem->GetSubType();

    auto typeIt = m_map_searchItem.find(bItemType);
    if (typeIt == m_map_searchItem.end())
        return;

    TSubTypeItemMap& map_itemSubType = typeIt->second;
    auto subTypeIt = map_itemSubType.find(bItemSubType);
    if (subTypeIt == map_itemSubType.end())
        return;

    TItemList& itemList = subTypeIt->second;

    for (auto it = itemList.begin(); it != itemList.end(); ++it)
    {
        LPITEM pListItem = *it;
        if (pListItem->GetID() == pItem->GetID())
        {
            itemList.erase(it);
            return;
        }
    }
}

bool FilterItem(LPITEM pItem, TPrivateShopSearchFilter& rFilter, bool bUseFilter)
{
    if (!pItem->GetPrivateShop())
    {
        sys_err("Could not find private shop for item %u", pItem->GetID());
        return false;
    }

    if (rFilter.iItemType >= 0)
    {
        if (pItem->GetType() != rFilter.iItemType)
            return false;
    }

    if (rFilter.iItemSubType >= 0)
    {
        if (pItem->GetSubType() != rFilter.iItemSubType)
            return false;
    }

    if (bUseFilter)
    {
        if (rFilter.dwVnum)
        {
            if (pItem->GetVnum() != rFilter.dwVnum)
                return false;
        }

        if (rFilter.iItemType == ITEM_WEAPON || rFilter.iItemType == ITEM_ARMOR)
        {
            if (rFilter.bMinRefine > 0)
            {
                if ((pItem->GetVnum() % 10) < rFilter.bMinRefine) return false;
            }

            if (rFilter.bMaxRefine > 0)
            {
                if ((pItem->GetVnum() % 10) > rFilter.bMaxRefine) return false;
            }
        }

        if (rFilter.iJob >= 0)
        {
            switch (rFilter.iJob)
            {
            case JOB_WARRIOR:
                if (pItem->GetAntiFlag() & ITEM_ANTIFLAG_WARRIOR)
                    return false;
                break;

            case JOB_ASSASSIN:
                if (pItem->GetAntiFlag() & ITEM_ANTIFLAG_ASSASSIN)
                    return false;
                break;

            case JOB_SHAMAN:
                if (pItem->GetAntiFlag() & ITEM_ANTIFLAG_SHAMAN)
                    return false;
                break;

            case JOB_SURA:
                if (pItem->GetAntiFlag() & ITEM_ANTIFLAG_SURA)
                    return false;

                break;
            }
        }

        if (rFilter.dwMinLevel > 0)
        {
            if (pItem->GetLevelLimit() && static_cast<DWORD>(pItem->GetLevelLimit()) < rFilter.dwMinLevel) return false;
        }

        if (rFilter.dwMaxLevel > 0)
        {
            if (static_cast<DWORD>(pItem->GetLevelLimit()) > rFilter.dwMaxLevel) return false;
        }

        if (rFilter.llMinGold > pItem->GetGoldPrice() ||
            rFilter.llMaxGold < pItem->GetGoldPrice())
        {
            return false;
        }

#ifdef WJ_PRIVATE_SHOP_CHEQUE
        if (rFilter.wMinCheque > pItem->GetChequePrice() ||
            rFilter.wMaxCheque < pItem->GetChequePrice())
        {
            return false;
        }
#endif
    }

    return true;
}

void CPrivateShopManager::SearchItem(LPDESC pCustomerDesc, TPrivateShopSearchFilter& rFilter, bool bUseFilter, TEMP_BUFFER* pBuf /* = nullptr */)
{
    TEMP_BUFFER buf {};
    DWORD dwCount = 0;
    const static size_t SAFE_RECV_BUFSIZE = 8192;

    /*
        1. Item vnum search
        2. Seller name search
        3. Item type/subtype search
    */
    if (rFilter.dwVnum)
    {
        TItemTable* pItemTable = ITEM_MANAGER::Instance().GetTable(rFilter.dwVnum);
        if (!pItemTable)
            return;

        rFilter.iItemType = pItemTable->bType;
        rFilter.iItemSubType = pItemTable->bSubType;

        auto typeIt = m_map_searchItem.find(rFilter.iItemType);
        if (typeIt == m_map_searchItem.end())
            return;

        TSubTypeItemMap& map_itemSubType = typeIt->second;
        auto subTypeIt = map_itemSubType.find(rFilter.iItemSubType);
        if (subTypeIt == map_itemSubType.end())
            return;

        TItemList& itemList = subTypeIt->second;

        for (const auto& pItem : itemList)
        {
            if (buf.size() + sizeof(TPrivateShopSearchData) > SAFE_RECV_BUFSIZE)
                break;

            if (FilterItem(pItem, rFilter, bUseFilter))
            {
                TPrivateShopSearchData item{};
                CopyItemData(pItem, item);

                if (pCustomerDesc)
                    buf.write(&item, sizeof(TPrivateShopSearchData));
                else if (pBuf)
                    pBuf->write(&item, sizeof(TPrivateShopSearchData));

                ++dwCount;
            }
        }
    }
    else if (rFilter.iItemType >= 0)
    {
        auto typeIt = m_map_searchItem.find(rFilter.iItemType);
        if (typeIt == m_map_searchItem.end())
            return;

        TSubTypeItemMap& map_itemSubType = typeIt->second;

        // Search by type-subtype
        if (rFilter.iItemSubType >= 0)
        {
            auto subTypeIt = map_itemSubType.find(rFilter.iItemSubType);
            if (subTypeIt == map_itemSubType.end())
                return;

            TItemList& itemList = subTypeIt->second;
            for (const auto& pItem : itemList)
            {
                if (buf.size() + sizeof(TPrivateShopSearchData) > SAFE_RECV_BUFSIZE)
                    break;

                if (FilterItem(pItem, rFilter, bUseFilter))
                {
                    TPrivateShopSearchData item{};
                    CopyItemData(pItem, item);

                    if (pCustomerDesc)
                        buf.write(&item, sizeof(TPrivateShopSearchData));
                    else if (pBuf)
                        pBuf->write(&item, sizeof(TPrivateShopSearchData));

                    ++dwCount;
                }
            }
        }
        // Search by type
        else
        {
            for (const auto& kv : map_itemSubType)
            {
                for (const auto& pItem : kv.second)
                {
                    if (buf.size() + sizeof(TPrivateShopSearchData) > SAFE_RECV_BUFSIZE)
                        break;

                    if (FilterItem(pItem, rFilter, bUseFilter))
                    {
                        TPrivateShopSearchData item{};
                        CopyItemData(pItem, item);

                        if (pCustomerDesc)
                            buf.write(&item, sizeof(TPrivateShopSearchData));
                        else if (pBuf)
                            pBuf->write(&item, sizeof(TPrivateShopSearchData));

                        ++dwCount;
                    }
                }
            }
        }
    }

    if (pCustomerDesc)
    {
        if (!dwCount)
            return;

        TPacketGCPrivateShop mainPacket{};
        mainPacket.bHeader = HEADER_GC_PRIVATE_SHOP;
        mainPacket.wSize = sizeof(TPacketGCPrivateShop) + dwCount * sizeof(TPrivateShopSearchData);
        mainPacket.bSubHeader = SUBHEADER_GC_PRIVATE_SHOP_SEARCH_RESULT;

        pCustomerDesc->BufferedPacket(&mainPacket, sizeof(TPacketGCPrivateShop));
        pCustomerDesc->LargePacket(buf.read_peek(), buf.size());
    }
}

private_shop_manager.h:
Genişlet Daralt Kopyala
#pragma once
#include <unordered_map>
#include <unordered_set>
#include "../../common/tables.h"
#include "packet.h"
#include <memory>

class CItem;
class CPrivateShop;
class TEMP_BUFFER;
class CPrivateShopManager : public singleton<CPrivateShopManager>
{
    public:

        CPrivateShopManager() = default;
        ~CPrivateShopManager() = default;

        void                Destroy();

        LPPRIVATE_SHOP        CreatePrivateShop(DWORD dwPID);
        LPPRIVATE_SHOP        GetPrivateShop(DWORD dwPID);
        LPPRIVATE_SHOP        GetPrivateShopByOwnerName(const char* c_szOwnerName);
        LPPRIVATE_SHOP        GetPrivateShopByVID(DWORD dwVID);
        bool                DeletePrivateShop(DWORD dwPID);
        DWORD                AllocVID() { return ++m_dwVIDCount; }

        bool                BuildPrivateShop(LPCHARACTER pShopOwner, const char* c_szTitle, DWORD dwPolyVnum, BYTE bTitleType, BYTE bPageCount, const std::vector<TPrivateShopItem>& c_vec_shopItem);
        void                BuildPrivateShopResult(DWORD dwPID, TPrivateShop* pPrivateShopTable, bool bSuccess);
        void                ClosePrivateShop(LPCHARACTER pShopOwner);

        void                SpawnPrivateShop(TPrivateShop* pTab, const std::vector<TPlayerPrivateShopItem>& c_vec_shopItem);
        void                DespawnPrivateShop(DWORD dwPID);

        bool                StopShopping(LPCHARACTER pShopViewer);

        void                ItemCheckin(LPCHARACTER pOwner, const TPlayerPrivateShopItem* c_pShopItem);
        void                ItemCheckout(LPCHARACTER pOwner, WORD wSrcPos, TItemPos TDstPos);

        bool                ItemTransaction(LPCHARACTER pCustomer, TPlayerPrivateShopItem* c_pShopItem);
        void                SendItemTransaction(const TPlayerPrivateShopItem* c_pShopItem, LPCHARACTER pCustomer);
        void                SendItemTransactionFailedResult(DWORD dwShopID, WORD wPos);
        void                SendItemTransfer(const TPlayerItem* c_pItem);
        void                SendItemExpire(LPITEM pItem);

        void                AddSearchItem(LPITEM pItem);
        void                RemoveSearchItem(LPITEM pItem);
        void                SearchItem(LPDESC pCustomerDesc, TPrivateShopSearchFilter& rFilter, bool bUseFilter, TEMP_BUFFER* pBuf = nullptr);

        typedef std::unordered_map<DWORD, std::unique_ptr<CPrivateShop> >    TPrivateShopMap;
        typedef std::unordered_map<DWORD, LPPRIVATE_SHOP>                    TPrivateShopVIDMap;
        typedef std::unordered_map<DWORD, TItemPrice>                        TMarketPriceMap;

        typedef std::unordered_set<LPITEM>                    TItemList;
        typedef std::unordered_map<BYTE, TItemList>            TSubTypeItemMap;
        typedef std::unordered_map<BYTE, TSubTypeItemMap>    TTypeItemMap;

    private:
        DWORD                m_dwVIDCount;
        TPrivateShopMap        m_map_privateShop;
        TPrivateShopVIDMap    m_map_privateShopVID;
        TTypeItemMap        m_map_searchItem;
};
 
burada eksik gördüm:
Genişlet Daralt Kopyala
void CPrivateShopManager::DespawnPrivateShop(DWORD dwPID)
{
    BYTE bSubHeader = PRIVATE_SHOP_GD_SUBHEADER_DESPAWN;
    DWORD dwOwner = dwPID;

    db_clientdesc->DBPacketHeader(HEADER_GD_PRIVATE_SHOP, 0, sizeof(BYTE) + sizeof(DWORD));
    db_clientdesc->Packet(&bSubHeader, sizeof(BYTE));
    db_clientdesc->Packet(&dwOwner, sizeof(DWORD));

    LPPRIVATE_SHOP pPrivateShop = GetPrivateShop(dwPID);
    if (!pPrivateShop)
    {
        sys_err("Cannot find private shop with id %u", dwPID);
        return;
    }
//eklenen kısım
    LPCHARACTER pOwner = CHARACTER_MANAGER::Instance().FindByPID(dwPID);
    if (pOwner)
        pOwner->ClosePrivateShop();
//eklenen kısım
    sys_log(0, "%s PRIVATE_SHOP: Shop entity despawned", pPrivateShop->GetOwnerName().c_str());
    DeletePrivateShop(dwPID);
}

DeletePrivateShop sadece managerdaki mapten siliyor, owner character'ındaki m_privateShopTable.dwOwner'ı sıfırlamıyor. Bu yüzden IsPrivateShopOwner hala true dönüyor.

Bende bunu ekledim ;
LPCHARACTER pOwner = CHARACTER_MANAGER::Instance().FindByPID(dwPID);
if (pOwner)
pOwner->ClosePrivateShop();


ClosePrivateShop() zaten memset(&amp;m_privateShopTable, 0, yapıyor yani dwOwner sıfırlanması ve IsPrivateShopun artık false dönmesi lazım .

Bir dene olmazsa tekrar kontrol ederiz.
 
Geri
Üst