-
Posts
2151 -
Joined
-
Last visited
-
Feedback
100%
Content Type
Forums
Store
Feature Plan
Release Notes
Docs
Events
Everything posted by Metin2 Dev
-
push
-
So why I cant write a DM to other user? For example. This is the Profile of WeedHex. There is no message Button [Hidden Content]
-
I have this account since 2017, didn't scammed people or spammed. I'm not very active on this board. So I don't understand it
-
@ Geoffrey_
-
Why I cant write a DM or other people send me a DM?
-
[Free] 3D Weapons (3D original file, needs to be converted and edited)
Metin2 Dev replied to Torres's topic in Weapons
nice release. If you want, I can show you how to convert it, so you can use it in Mt2. I also would like if you tell me where you find this kind of modells -
MariaDB lib on Windows
Metin2 Dev replied to Metin2 Dev's topic in Community Support - Questions & Answers
push -
I wanted to use now MariaDB instead of mysql5.6 I installed already MariaDB and can start MariaDB and connect also with Navicat to my Database. But when I start my Server on Windows, it cannot connect to MariaDB. I think its maybe because of the mysqlclient.lib that is in Visual Studio linked to the game.exe and db.exe mysqlclient.lib is for old Mysql5.6 but I need now one for mariadb. Can someone share the mariaclient.lib
-
No, as you can see in LoginData.cpp constructor we have: m_bAllowLoginByKey = true; // We allow loginByKey by default (so the first login doesn't fail) This is exactly for that. There is not problem because as far as i've read in the code that part can't be exploited, correct me if I'm wrong. Also I want to say this is not a common exploit everyone can use. I posted it because there is a turkish hack that has a function called "Channel changer" that use exactly this exploit to change channel and skip the time checks. Didn't want to post a demonstration because last time I posted an exploit people abused on some servers and hurt them. This is an exception because not everyone knows how to implement this from outside the binary This is how the exploit works (this is only for demonstration, you need extra steps to reproduce on a live server) : 1. Create a functions like this: void CPythonNetworkStream::SendLoginByKeyExploitPacket(BYTE bCharacterSlot, const char* c_szAddr, uint32_t uPort) { __DirectEnterMode_Set(bCharacterSlot, true); Connect(c_szAddr, uPort); } 2. Call it like this: - bCharacterSlot = your character slot, eg. 0 - szAddr = server ip - uPort = the port in which you want to go 3. Go on a map1 and open general store on ch1 4. After you buy an item from the general store, you imediatly call the login by key function with the port for ch2 5. You will be teleported to ch2 and all the checks after buying an item will be skipped 6. If the server does not extra checks you might see you got the item but you still have the money
-
As you probably know, there's an exploit that players use to change channels by abusing the LoginByKey function (a hack function). This function lacks any limitations, any connection can use it at any time. When combined with poorly written systems, it can be used to duplicate items or yang. I have already shared the fix privately with many people. At one point, someone even posted it on a forum, but it appears that the content has since been deleted. I’ve now been informed that this same user is selling the “fix”, despite the fact that it isn’t even theirs. The fix isn’t perfect, but it works. Essentially, it ensures that only players with a valid logout can use LoginByKey, as it should be. // common/tables.h // 1. Search: typedef struct SLogoutPacket { char login[LOGIN_MAX_LEN + 1]; char passwd[PASSWD_MAX_LEN + 1]; } TLogoutPacket; // 1. Replace with: typedef struct SLogoutPacket { char login[LOGIN_MAX_LEN + 1]; char passwd[PASSWD_MAX_LEN + 1]; bool bCanUseLoginByKey; } TLogoutPacket; // db/ClientManagerLogin.cpp // 1. Search: (void CClientManager::QUERY_LOGIN_BY_KEY) if (memcmp(pkLoginData->GetClientKey(), p->adwClientKey, sizeof(DWORD) * 4)) { const DWORD* pdwClientKey = pkLoginData->GetClientKey(); sys_log(0, "LOGIN_BY_KEY client key differ %s %lu %lu %lu %lu, %lu %lu %lu %lu", r.login, p->adwClientKey[0], p->adwClientKey[1], p->adwClientKey[2], p->adwClientKey[3], pdwClientKey[0], pdwClientKey[1], pdwClientKey[2], pdwClientKey[3]); pkPeer->EncodeReturn(HEADER_DG_LOGIN_NOT_EXIST, dwHandle); return; } // 1. Add after: if (!pkLoginData->IsAllowLoginByKey()) { sys_err("LOGIN_BY_KEY without request %s", r.login); // To track them down sys_log(0, "LOGIN_BY_KEY without request %s %lu", r.login, p->dwLoginKey); TPacketDGLoginAlready ptog; strlcpy(ptog.szLogin, szLogin, sizeof(ptog.szLogin)); pkPeer->EncodeHeader(HEADER_DG_LOGIN_ALREADY, dwHandle, sizeof(TPacketDGLoginAlready)); pkPeer->Encode(&ptog, sizeof(TPacketDGLoginAlready)); return; } pkLoginData->SetAllowLoginByKey(false); // db/ClientManagerLogin.cpp // 2. Search: (void CClientManager::QUERY_LOGOUT) CLoginData* pLoginData = GetLoginDataByLogin(packet->login); if (pLoginData == NULL) return; // 2. Add after: pLoginData->SetAllowLoginByKey(packet->bCanUseLoginByKey); // db/LoginData.cpp // 1. Inside constructor add: (CLoginData::CLoginData()) m_bAllowLoginByKey = true; // We allow loginByKey by default (so the first login doesn't fail) // db/LoginData.h // 1. Add: public: bool IsAllowLoginByKey() const { return m_bAllowLoginByKey; } void SetAllowLoginByKey(bool bFlag) { m_bAllowLoginByKey = bFlag; } private: bool m_bAllowLoginByKey; // game/char.cpp // 1. Somwhere inside void CHARACTER::Initialize() add: m_bCanUseLoginByKey = false; // 2. Inside your warp functions search: (WarpSet, ChangeChannel, etc) Stop(); Save(); // 2. Add before that: m_bCanUseLoginByKey = true; // game/char.h // 1. Add: public: bool CanUseLoginByKey() const { return m_bCanUseLoginByKey; } protected: bool m_bCanUseLoginByKey; // game/desc.cpp // 1. Search: (void DESC::Destroy()) if (m_lpCharacter) { m_lpCharacter->Disconnect("DESC::~DESC"); m_lpCharacter = NULL; } // 1. Replace with: bool bCanUseLoginByKey = true; if (m_lpCharacter) { bCanUseLoginByKey = m_lpCharacter->CanUseLoginByKey(); m_lpCharacter->Disconnect("DESC::~DESC"); m_lpCharacter = NULL; } // game/desc.cpp // 2. Search: (void DESC::Destroy()) if (!g_bAuthServer) { if (m_accountTable.login[0] && m_accountTable.passwd[0]) { TLogoutPacket pack; strlcpy(pack.login, m_accountTable.login, sizeof(pack.login)); strlcpy(pack.passwd, m_accountTable.passwd, sizeof(pack.passwd)); db_clientdesc->DBPacket(HEADER_GD_LOGOUT, m_dwHandle, &pack, sizeof(TLogoutPacket)); } } // 2. Change it like this: if (!g_bAuthServer) { if (m_accountTable.login[0] && m_accountTable.passwd[0]) { TLogoutPacket pack; strlcpy(pack.login, m_accountTable.login, sizeof(pack.login)); strlcpy(pack.passwd, m_accountTable.passwd, sizeof(pack.passwd)); pack.bCanUseLoginByKey = bCanUseLoginByKey; db_clientdesc->DBPacket(HEADER_GD_LOGOUT, m_dwHandle, &pack, sizeof(TLogoutPacket)); } } // game/input_db.cpp // 1. Search: (void CInputDB::LoginSuccess) if (!d) { sys_log(0, "CInputDB::LoginSuccess - cannot find handle [%s]", pTab->login); TLogoutPacket pack; strlcpy(pack.login, pTab->login, sizeof(pack.login)); db_clientdesc->DBPacket(HEADER_GD_LOGOUT, dwHandle, &pack, sizeof(pack)); return; } if (strcmp(pTab->status, "OK")) { sys_log(0, "CInputDB::LoginSuccess - status[%s] is not OK [%s]", pTab->status, pTab->login); TLogoutPacket pack; strlcpy(pack.login, pTab->login, sizeof(pack.login)); db_clientdesc->DBPacket(HEADER_GD_LOGOUT, dwHandle, &pack, sizeof(pack)); LoginFailure(d, pTab->status); return; } // 1. Replace with: if (!d) { sys_log(0, "CInputDB::LoginSuccess - cannot find handle [%s]", pTab->login); TLogoutPacket pack; strlcpy(pack.login, pTab->login, sizeof(pack.login)); pack.bCanUseLoginByKey = false; db_clientdesc->DBPacket(HEADER_GD_LOGOUT, dwHandle, &pack, sizeof(pack)); return; } if (strcmp(pTab->status, "OK")) { sys_log(0, "CInputDB::LoginSuccess - status[%s] is not OK [%s]", pTab->status, pTab->login); TLogoutPacket pack; strlcpy(pack.login, pTab->login, sizeof(pack.login)); pack.bCanUseLoginByKey = false; db_clientdesc->DBPacket(HEADER_GD_LOGOUT, dwHandle, &pack, sizeof(pack)); LoginFailure(d, pTab->status); return; }
- 4 replies
-
- 22
-
-
-
-
-
This is a solid release for users seeking a quick update from the outdated browser bundled in the binary, which is plagued with numerous issues. However, I do not recommend switching to WebView2 if you are already using Chromium. Despite being based on Chromium, WebView2 comes with several limitations: 1. Dependency on Edge Runtime: WebView2 requires the Microsoft Edge runtime, which is only available on Windows 10 and newer. There is still a significant number of users running Windows 7. 2. Restricted Environments: In certain restricted or controlled environments, such as corporate or shared workstations, the Edge runtime may not be installed or allowed. (Yes, some users do play Metin2 from work machines.) 3. Limited Control over Chromium Internals: Unlike a full Chromium integration, WebView2 does not offer full access to internal features such as cache management, cookie control, or deep customization.
-
Greetings community, I’d like to share a pair of tools that I’ve been using recently to create high-quality custom icons for metin2. These tools leverage AI to speed up the process while offering impressive results with minimal manual effort. Whether you’re a developer, modder, or just someone looking to personalize your server, this may save you considerable time. 1. AI Icon Generator [Hidden Content] This tool uses generative AI to create 512x512 pixel-style icons based on a short text prompt. You can describe what kind of item or symbol you want (e.g., "phoenix ring", "mystic blue potion") and it will generate multiple icons to choose from. You can keep re-rolling until you get one that suits your needs. I recomend using "Game Art Icon" style. 2. Background Remover [Hidden Content] After generating your icon, you’ll often want to remove any background to properly integrate it into the game. This tool does a clean and accurate background removal in seconds. Example Workflow Here’s a step-by-step example to create a new icon for a fantasy potion: Goal: Create a custom “Dark Elixir” potion icon. 1. Generate the Icon - Visit: [Hidden Content] - Prompt used: dark purple potion - Review generated results and save the one that fits best. - Result: [Hidden Content] 2. Remove the Background - Go to: [Hidden Content] - Upload the downloaded image. - Download the processed PNG with transparent background. - Result: [Hidden Content] 3. Prepare for metin2 client - Resize it to 32x32, convert it to tga format and implement it in the client 4. Result [Hidden Content] Let me know if you find this useful or if you have your own methods for icon creation. I’m open to hearing what other tools or workflows you’ve had success with. Regards, Mr. Tiger
- 1 reply
-
- 13
-
-
-
-
Bro we live in 2025. Get some cheap Server for 3-5$ and all your friends can join.
-
You can find it in the leaked source files at these locations: kraizy/dev/Srcs/Tools/WorldEditor kraizy/novaline/Srcs/Tools/WorldEditor
-
Metinstone in Shield and Helmet
Metin2 Dev replied to mrscale's topic in Community Support - Questions & Answers
In constants.cpp you also have to change this. const int aiArmorSocketQty[ARMOR_NUM_TYPES] = { 3, // ARMOR_BODY, 1, // ARMOR_HEAD, 1, // ARMOR_SHIELD, 0, // ARMOR_WRIST, 0, // ARMOR_FOOTS, 0 // ARMOR_ACCESSORY }; ARMOR_HEAD and ARMOR_SHIELD from 1 to 3 -
Draw circle on ground
Metin2 Dev replied to Metin2 Dev's topic in Community Support - Questions & Answers
Thank you very much, now it works well. One question more. Is it easy to edit the code, so the circle follow the terrain height or depth? -
Draw circle on ground
Metin2 Dev replied to Metin2 Dev's topic in Community Support - Questions & Answers
Still same problem -
Draw circle on ground
Metin2 Dev replied to Metin2 Dev's topic in Community Support - Questions & Answers
push -
Draw circle on ground
Metin2 Dev replied to Metin2 Dev's topic in Community Support - Questions & Answers
I changed the code like that void CPythonCharacterManager::DrawCircle() { CInstanceBase* pMainInstance = CPythonPlayer::Instance().NEW_GetMainActorPtr(); if (!pMainInstance) return; static CScreen screen; STATEMANAGER.SetRenderState(D3DRS_TEXTUREFACTOR, D3DCOLOR_XRGB(50, 50, 255)); screen.RenderCircle2d(0.0f, 0.0f, 0.0f, 100.0f); } But still same problem, when I call the function nothing happens. I debuged it already and set a breakpoint at the function and he call it fully. -
Currently im trying to draw a circle with my player as center point and if he moves, the circle should also move with him. But my problem is, that I dont know how to do it. So far this is the code: void CPythonCharacterManager::DrawCircle() { CInstanceBase* pMainInstance = CPythonPlayer::Instance().NEW_GetMainActorPtr(); if (!pMainInstance) return; TPixelPosition pixelPos; pMainInstance->NEW_GetPixelPosition(&pixelPos); static CScreen screen; STATEMANAGER.SetRenderState(D3DRS_TEXTUREFACTOR, D3DCOLOR_XRGB(50, 50, 255)); const int iSteps = 60; const float fRadius = 200; screen.RenderCircle2d(pixelPos.x, pixelPos.y, pixelPos.z, fRadius, iSteps); } When I call the code, nothing happens. Tried also with other D3DRender state type, but either strange visual bugs appear or nothing happens
-
Refresh database cache from outside of game
Metin2 Dev replied to jaed17's topic in Community Support - Questions & Answers
Soo, you want the cache for a specific player to be saved and flushed instant? if so: // in cmd_gm.cpp // Search: ACMD(do_flush) // Replace tch->Save(); // with tch->SaveReal(); And use command /flush player_id u can find playerid in player.sql -
Problem with mouse click
Metin2 Dev replied to elyzeumozart's topic in Community Support - Questions & Answers
Do you use Directx9 ? From what I remember this is a problem only on directx9.
