Informations
Jump to content

Lorem Ipsum...

Click to Dismiss this Notification
Ładowanie danych...

How to Add 4th Socket (Stone Slot) to Items + Bug Fixes (Server & Client)


Recommended Posts

  • Premium+

301403_1a83e87e814eb7bf3c1d796e92bd86df.

nMQDOg.png

 

 

As most server administrators know, the default limit of 3 socket slots on Metin2 PvP servers can create major balancing issues. When players maximize their gear with Warrior, Sura, and Ninja resistance or against-stones, they are often left completely defenseless against Shamans.

To restore class balance and create a fairer PvP environment, this guide will show you how to expand your item system to support 4 Sockets. We will go through the process step-by-step, covering Server Source, DB Source, Client Source, and essential bug fixes.

📁 Section 1: Server-Side Source Changes

1️⃣ Modify Item Configuration

Open common/item_length.h and search for the maximum socket constant:

C++
ITEM_SOCKET_MAX_NUM = 3,

Change the value from 3 to 4:

C++
ITEM_SOCKET_MAX_NUM = 4,

2️⃣ Update Player Item Loading

Open db/src/ClientManagerPlayer.cpp and search for the following line:

C++
str_to_number(item.alSockets[2], row[cur++]);

Directly underneath it, add the tracking line for the 4th socket:

C++
str_to_number(item.alSockets[3], row[cur++]);

3️⃣ Update the Player Item SQL Queries

Still inside db/src/ClientManagerPlayer.cpp, locate the following SQL query segment:

SQL
SELECT id,window+0,pos,count,vnum,socket0,socket1,socket2 ,attrtype0,attrvalue0,attrtype1,attrvalue1,attrtyp e2,attrvalue2,attrtype3,attrvalue3,attrtype4,attrv alue4,attrtype5,attrvalue5,attrtype6,attrvalue6

Replace it entirely with this updated query to include socket3:

SQL
SELECT id,window+0,pos,count,vnum,socket0,socket1,socket2,socket3,attrtype0,attrvalue0,attrtype1,attrvalue1,attrtype2,attrvalue2,attrtype3,attrvalue3,attrtype4,attrvalue4,attrtype5,attrvalue5,attrtype6,attrvalue6

Now, find the second instance of the item selection query within the same file:

SQL
SELECT id,window+0,pos,count,vnum,socket0,socket1,socket2,attrtype0,attrvalue0,attrtype1,attrvalue1,attrtype2,attrvalue2,attrtype3,attrvalue3,attrtype4,attrvalue4,attrtype5,attrvalue5,attrtype6,attrvalue6

Replace it with:

SQL
SELECT id,window+0,pos,count,vnum,socket0,socket1,socket2,socket3,attrtype0,attrvalue0,attrtype1,attrvalue1,attrtype2,attrvalue2,attrtype3,attrvalue3,attrtype4,attrvalue4,attrtype5,attrvalue5,attrtype6,attrvalue6

4️⃣ Update Client Manager Queries

Open db/src/ClientManager.cpp and search for:

SQL
SELECT id, window+0, pos, count, vnum, socket0, socket1, socket2

Modify it to fetch the fourth socket field:

SQL
SELECT id, window+0, pos, count, vnum, socket0, socket1, socket2, socket3

5️⃣ Update Cache Serialization

Open db/src/Cache.cpp and locate this line:

C++
iLen += snprintf(szColumns + iLen, sizeof(szColumns)  iLen, , socket0, socket1, socket2, socket3);

Replace that block completely with the following implementation:

C++
if (isSocket)
{
        iLen += snprintf(szColumns + iLen, sizeof(szColumns) - iLen, ", socket0, socket1, socket2, socket3");
        iValueLen += snprintf(szValues + iValueLen, sizeof(szValues) - iValueLen,
                        ", %lu, %lu, %lu, %lu", p->alSockets[0], p->alSockets[1], p->alSockets[2], p->alSockets[3]);
        iUpdateLen += snprintf(szUpdate + iUpdateLen, sizeof(szUpdate) - iUpdateLen,
                        ", socket0=%lu, socket1=%lu, socket2=%lu, socket3=%lu", p->alSockets[0], p->alSockets[1], p->alSockets[2], p->alSockets[3]);
}

6️⃣ Configure Default Item Sockets

Open game/src/constants.cpp and search for aiWeaponSocketQty[WEAPON_NUM_TYPES]. Update the item type configuration array to allow 4 slots:

 

C++
const int32_t aiWeaponSocketQty[WEAPON_NUM_TYPES] =
{
    4, // WEAPON_SWORD,
    4, // WEAPON_DAGGER,
    4, // WEAPON_BOW,
    4, // WEAPON_TWO_HANDED,
    4, // WEAPON_BELL,
    4, // WEAPON_FAN,
    0, // WEAPON_ARROW,
    0, // WEAPON_MOUNT_SPEAR
};

Next, locate aiArmorSocketQty[ARMOR_NUM_TYPES] and change the body armor slot value to 4:

C++
const int32_t aiArmorSocketQty[ARMOR_NUM_TYPES] =
{
    4, // ARMOR_BODY,
    1, // ARMOR_HEAD,
    1, // ARMOR_SHIELD,
    0, // ARMOR_WRIST,
    0, // ARMOR_FOOTS,
    0  // ARMOR_ACCESSORY
};

🖥️ Section 2: Client-Side Source Changes

7️⃣ Update Client Max Sockets

Open your client source and navigate to UserInterface/GameType.h. Search for ITEM_SOCKET_SLOT_MAX_NUM and change its value from 3 to 4.

💾 Section 3: Database Update (MySQL)

⚠️ CRITICAL WARNING: Even though your source code is ready, items will not accept a 4th stone until your database structure is modified. You must update your item_proto via Navicat / MySQL. Do not change the client-side locale item_proto manually for this step, or you risk breaking item glows!

Run the following SQL query to automatically shift all 3-socket items to 4 sockets:

SQL
UPDATE item_proto SET socket_pct=4 WHERE socket_pct=3;

🐛 Section 4: Critical Bug Fixes

Adding a 4th socket exposes a few legacy bugs in the Metin2 codebase. Apply the following fixes to ensure system stability.

📌 Fix A: The Warehouse / Storeroom Bug

Description: Storing an item with 4 stones inside the warehouse causes the 4th stone to disappear or resets the item slots back to 3 upon item retrieval.

Open db/src/ClientManager.cpp and search for:

C++
void CClientManager::QUERY_ITEM_SAVE(CPeer * pkPeer, const char * c_pData)

Look slightly below it for the following query string:

C++
REPLACE INTO item%s (id, owner_id, window, pos, count, vnum, socket0, socket1, socket2,

Change it to include socket3:

C++
REPLACE INTO item%s (id, owner_id, window, pos, count, vnum, socket0, socket1, socket2, socket3,

Now, locate the matching VALUES string directly underneath:

C++
VALUES(%u, %u, %d, %d, %u, %u, %ld, %ld, %ld, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)

Replace it with an additional parameter placeholder:

C++
VALUES(%u, %u, %d, %d, %u, %u, %ld, %ld, %ld, %ld, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)

Finally, find where the socket data array is passed:

C++
p->alSockets[2],

Add the fourth slot index directly underneath it:

C++
p->alSockets[3],

📌 Fix B: Item Linking / Glass of Insight Bug

Description: Items linked in chat (via Glass of Insight) will show up blank or won't display tooltips when clicked because the data string length changed.

1. Open UserInterface/PythonPlayerModule.cpp

Find playerGetItemLink and replace the function block completely:

C++
PyObject * playerGetItemLink(PyObject * poSelf, PyObject * poArgs)
{
        TItemPos Cell;
 
        switch (PyTuple_Size(poArgs))
        {
        case 1:
                if (!PyTuple_GetInteger(poArgs, 0, &Cell.cell))
                        return Py_BuildException();
                break;
        case 2:
                if (!PyTuple_GetByte(poArgs, 0, &Cell.window_type))
                        return Py_BuildException();
                if (!PyTuple_GetInteger(poArgs, 1, &Cell.cell))
                        return Py_BuildException();
                break;
        default:
                return Py_BuildException();
        }
        const TItemData * pPlayerItem = CPythonPlayer::Instance().GetItemData(Cell);
        CItemData * pItemData = NULL;
        char buf[1024];
 
        if (pPlayerItem && CItemManager::Instance().GetItemDataPointer(pPlayerItem->vnum, &pItemData))
        {
                char itemlink[256];
                int len;
                bool isAttr = false;
 
                len = snprintf(itemlink, sizeof(itemlink), "item:%x:%x:%x:%x:%x:%x:%x:%x",
                                pPlayerItem->vnum, pPlayerItem->flags,
                                pPlayerItem->alSockets[0], pPlayerItem->alSockets[1], pPlayerItem->alSockets[2] , pPlayerItem->alSockets[3],  pPlayerItem->alSockets[4],  pPlayerItem->alSockets[5]);
 
                for (int i = 0; i < ITEM_ATTRIBUTE_SLOT_MAX_NUM; ++i)
                        if (pPlayerItem->aAttr[i].bType != 0)
                        {
                                len += snprintf(itemlink + len, sizeof(itemlink) - len, ":%x:%d",
                                                pPlayerItem->aAttr[i].bType, pPlayerItem->aAttr[i].sValue);
                                isAttr = true;
                        }
 
 
                if( GetDefaultCodePage() == CP_ARABIC ) {
                        if (isAttr)
                                //"item:vnum:flag:socket0:socket1:socket2"
                                snprintf(buf, sizeof(buf), " |h|r[%s]|cffffc700|H%s|h", pItemData->GetName(), itemlink);
                        else
                                snprintf(buf, sizeof(buf), " |h|r[%s]|cfff1e6c0|H%s|h", pItemData->GetName(), itemlink);
                } else {
                        if (isAttr)
                                //"item:vnum:flag:socket0:socket1:socket2"
                                snprintf(buf, sizeof(buf), "|cffffc700|H%s|h[%s]|h|r", itemlink, pItemData->GetName());
                        else
                                snprintf(buf, sizeof(buf), "|cfff1e6c0|H%s|h[%s]|h|r", itemlink, pItemData->GetName());
                }
        }
        else
                buf[0] = '\0';
 
        return Py_BuildValue("s", buf);
}

2. Open UserInterface/PythonChatModule.cpp

Find chatGetLinkFromHyperlink and replace it entirely with:

C++
PyObject * chatGetLinkFromHyperlink(PyObject * poSelf, PyObject * poArgs)
{
        char * szHyperlink;
       
        if (!PyTuple_GetString(poArgs, 0, &szHyperlink))
                return Py_BuildException();
 
        std::string stHyperlink(szHyperlink);
        std::vector<std::string> results;
 
        split_string(stHyperlink, ":", results, false);
 
        // item:vnum:flag:socket0:socket1:socket2:socket3:socket4:socket5
        if (0 == results[0].compare("item"))
        {
                if (results.size() < 9)
                        return Py_BuildValue("s", "");
 
                CItemData * pItemData = NULL;
 
                if (CItemManager::Instance().GetItemDataPointer(htoi(results[1].c_str()), &pItemData))
                {
                        char buf[1024] = { 0 };
                        char itemlink[256];
                        int len;
                        bool isAttr = false;
 
                        len = snprintf(itemlink, sizeof(itemlink), "item:%x:%x:%x:%x:%x:%x:%x:%x",
                                        htoi(results[1].c_str()),
                                        htoi(results[2].c_str()),
                                        htoi(results[3].c_str()),
                                        htoi(results[4].c_str()),
                                        htoi(results[5].c_str()),
                                        htoi(results[6].c_str()),
                                        htoi(results[7].c_str()),
                                        htoi(results[8].c_str()));
 
                        if (results.size() >= 11)
                        {
                                for (int i = 9; i < results.size(); i += 2)
                                {
                                        len += snprintf(itemlink + len, sizeof(itemlink) - len, ":%x:%d",
                                                        htoi(results[i].c_str()),
                                                        atoi(results[i+1].c_str()));
                                        isAttr = true;
                                }
                        }
 
                        if (isAttr)
                                //"item:vnum:flag:socket0:socket1:socket2"
                                snprintf(buf, sizeof(buf), "|cffffc700|H%s|h[%s]|h|r", itemlink, pItemData->GetName());
                        else
                                snprintf(buf, sizeof(buf), "|cfff1e6c0|H%s|h[%s]|h|r", itemlink, pItemData->GetName());
 
                        return Py_BuildValue("s", buf);
                }
        }
 
        return Py_BuildValue("s", "");
}

3. Open root/uiinventory.py

Search for the attribute index evaluation check:

Python
if attrCount<4:

Change the condition requirement to 5:

Python
if attrCount<5:

4. Open root/uitooltip.py

Search for def SetHyperlinkItem(self, tokens): and update it with the following adjusted parsing token rule block:

Python
def SetHyperlinkItem(self, tokens):
        minTokenCount = 3 + player.METIN_SOCKET_MAX_NUM
        maxTokenCount = minTokenCount + 2 * player.ATTRIBUTE_SLOT_MAX_NUM
        if tokens and len(tokens) >= minTokenCount and len(tokens) <= maxTokenCount:
                head, vnum, flag = tokens[:3]
                itemVnum = int(vnum, 16)
                metinSlot = [int(metin, 16) for metin in tokens[3:9]]
 
                rests = tokens[9:]
                if rests:
                        attrSlot = []
 
                        rests.reverse()
                        while rests:
                                key = int(rests.pop(), 16)
                                if rests:
                                        val = int(rests.pop())
                                        attrSlot.append((key, val))
 
                        attrSlot += [(0, 0)] * (player.ATTRIBUTE_SLOT_MAX_NUM - len(attrSlot))
                else:
                        attrSlot = [(0, 0)] * player.ATTRIBUTE_SLOT_MAX_NUM
 
                self.ClearToolTip()
                self.AddItemData(itemVnum, metinSlot, attrSlot)
 
                ItemToolTip.OnUpdate(self)

📌 Fix 😄 Mount / Unique Item Expiration Bug

Description: Increasing ITEM_SOCKET_MAX_NUM directly shifts the evaluation calculations for unique timers, causing mount durations to break.

 

To prevent this, hardcode the historical references within the structure offset definition block. Locate enum EItemUniqueSockets and adjust the math logic:

Find:

C++
enum EItemUniqueSockets
{
    ITEM_SOCKET_UNIQUE_SAVE_TIME = ITEM_SOCKET_MAX_NUM - 2,
    ITEM_SOCKET_UNIQUE_REMAIN_TIME = ITEM_SOCKET_MAX_NUM - 1
};

Replace with:

C++
enum EItemUniqueSockets
{
    ITEM_SOCKET_UNIQUE_SAVE_TIME = 3 - 2,
    ITEM_SOCKET_UNIQUE_REMAIN_TIME = 3 - 1
};

🎉 Congratulations! Your implementation is complete. Recompile your server and client binaries, restart your database services, and enjoy a fully functional, bug-free 4-Socket system! Feel free to drop a reply below if you have any questions.

 

This is the hidden content, please

This is the hidden content, please

This is the hidden content, please

This is the hidden content, please

This is the hidden content, please

 

Link to comment
Share on other sites


spacer.png

Hi TechroomsBOT 👋

Thanks for starting a new topic on Techrooms – Blockchain, Programming, Gaming & Crypto Forum!  
If you’re new here — welcome. If you’ve been around for a while — great to have you back 😊

To help you get the most out of TechRooms, here are a few useful places to explore:

────────────────────────────────────
💎 Premium Membership (Optional)
Support the community and unlock extra perks:

🚫 Ad-free browsing  
Faster access & priority support  
📊 Private analysis & signals  
🧪 Early access to beta features & tools  
📥 Downloadable premium resources  

🎟️ Upgrade here: Premium Link
────────────────────────────────────

🧠 Popular Sections You Might Like

📊 Crypto Signals & Market Analysis  
Get free signals and market insights: Signals

💾 Tech Tools & Programs  
Automation, software, utilities & security tools: Tools Techrooms

🗣️ Discussions & Q&A  
Ask questions, share knowledge, help others: Forum

📚 Tech Book Library  
Books, guides and resources for members: Books

📚 Quizzes  
Members Quizzes: Quizzes

🎓 Learning & Courses  
Blockchain, security, coding and more: Blockchain Courses

🧠 Hacking & Firewall Courses 
Hacking, security, firewall and more: Firewall Courses

🪙 Earn Tokens for Posting  
Create valuable content and get rewarded

🃏 Blackjack  
Take a break and play: Blackjack

💖 Support via Crypto Donation (Optional)
Cosmos Wallet: 
cosmos1p5sjqcu3gp9vkjdyc9uee2mw4a4zvjvqz2lj2g 
Donate: Donate

📜 Forum Rules  
Please read before posting: Techrooms Rules

────────────────────────────────────
Stay connected. Stay ahead. Stay TechRooms. 🚀

 

Link to comment
Share on other sites


Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.

spacer.png

Disable AdBlock
The popup will be closed in 5 seconds...