-
Posts
153 -
Joined
-
Last visited
-
Days Won
2 -
Feedback
0%
Kaptan Yosun last won the day on October 11 2025
Kaptan Yosun had the most liked content!
About Kaptan Yosun

- Birthday January 24
Informations
-
Gender
Male
-
Country
Thailand
Kaptan Yosun's Achievements
-
official Official Client Locale String[REVERSED]
Kaptan Yosun replied to Mali's topic in Features & Metin2 Systems
-
[C++] Upgrade Client Source to DirectX 9Ex
Kaptan Yosun replied to Kaptan Yosun's topic in Guides & HowTo
Only in which specific function causes issue. Do not pass that argument everwhere -
[C++] Upgrade Client Source to DirectX 9Ex
Kaptan Yosun replied to Kaptan Yosun's topic in Guides & HowTo
You did not pass D3DUSAGE_DYNAMIC arguments to necessary places. -
Fix: // Edited again, we just need to change the order the logic We’re capturing the mouse before checking ImGui, so when ImGui consumes the click, capture is never released, breaking the title bar close button. Find case WM_LBUTTONDOWN: #ifdef __BL_IMGUI__ if (GetCapture() != hWnd) SafeSetCapture(); if (ImGui::GetIO().WantCaptureMouse) return 0; #else SafeSetCapture(); #endif Change case WM_LBUTTONDOWN: #ifdef __BL_IMGUI__ if (ImGui::GetIO().WantCaptureMouse) return 0; if (GetCapture() != hWnd) SafeSetCapture(); #else SafeSetCapture(); #endif Find case WM_LBUTTONUP: #ifdef __BL_IMGUI__ if (GetCapture() != hWnd) SafeSetCapture(); if (ImGui::GetIO().WantCaptureMouse) return 0; #endif Change case WM_LBUTTONUP: #ifdef __BL_IMGUI__ if (ImGui::GetIO().WantCaptureMouse) return 0; if (GetCapture() != hWnd) SafeSetCapture(); #endif
-
While working with the GF-based atlas mark system, I noticed a 1-pixel north-west offset on the 2×2 WhiteMark dots of NPCs that have an active quest on the minimap. This offset was visible only on quest-marked NPCs; normal NPC dots looked correct at first glance. Why Was This Not Noticed Before? With the old atlas data and previous loading functions, atlas mark positions were processed using low-resolution / coarse coordinates, which effectively masked the issue in practice. In the newer GF __LoadAtlasMarkInfo implementation, atlas coordinates are used more accurately and directly, which made this previously unnoticed alignment issue visible. For example, this is an entry from the old Server\Binary\share\locale\xx\map\metin2_map_c1\npc.txt, where the coordinates are written roughly: m 732 390 0 0 0 0 1m 100 1 9009 And this is the corresponding entry from the new Client\Binary\pack\locale\locale\xx\map\metin2_map_c1_point.txt, where the coordinates are written precisely (×100): #index x y npc_vnum enable_helper icon 0 73200 39000 9009 0 0 This higher-precision data likely exposed floating-point alignment differences. In other words, this is not a bug introduced by the new function, but rather a previously existing logical issue that was hidden and has now surfaced. Cause During the atlas mark loading stage: Half of the sprite width/height was subtracted, applying early centering During rendering, the sprite was already assumed to be centered This resulted in: Atlas mark positions being centered twice A visible 1-pixel north-west shift, especially in the quest highlight pixel inside the WhiteMark Solution The responsibility between logic layers was clearly separated: Atlas mark positions are now stored as center coordinates Sprite size–dependent half-width / half-height offsets are applied only during rendering As a result: NPC dots Quest highlight pixels Waypoint and target markers are all aligned using the same reference point. Result The quest pixel offset on WhiteMark is completely fixed Atlas and minimap rendering logic is now more consistent Future refactors or visual changes are less likely to reintroduce similar issues Client\Source\UserInterface\PythonMiniMap.cpp: // Search @@ void CPythonMiniMap::__LoadAtlasMarkInfo() aAtlasMarkInfo.m_fScreenX = aAtlasMarkInfo.m_fX / m_fAtlasMaxX * m_fAtlasImageSizeX - (float)m_WhiteMark.GetWidth() / 2.0f; aAtlasMarkInfo.m_fScreenY = aAtlasMarkInfo.m_fY / m_fAtlasMaxY * m_fAtlasImageSizeY - (float)m_WhiteMark.GetHeight() / 2.0f; // Change /* - ATLAS_MARK_INFO [REFACTOR] ------------------------ * [KaptanYosun Dev Note] * Atlas mark positions must be stored as CENTER coordinates. * * The previous implementation subtracted half of the mark size * here, effectively converting the position to top-left space * too early. This caused double-centering during rendering and * resulted in a 1px north-west offset in quest-highlight pixels. * * Centering (subtracting half width/height) is now applied ONLY * at render time, ensuring consistent alignment between: * - NPC dots * - Quest highlight pixels * - Waypoints and target marks * * Rule: store logical positions as center, apply sprite offsets * only in the rendering layer. */ aAtlasMarkInfo.m_fScreenX = aAtlasMarkInfo.m_fX / m_fAtlasMaxX * m_fAtlasImageSizeX; aAtlasMarkInfo.m_fScreenY = aAtlasMarkInfo.m_fY / m_fAtlasMaxY * m_fAtlasImageSizeY; /* ----------------------------------------------------- */ // Search @@ void CPythonMiniMap::RenderAtlas(float fScreenX, float fScreenY) STATEMANAGER.SetRenderState(D3DRS_TEXTUREFACTOR, CInstanceBase::GetIndexedNameColor(CInstanceBase::NAMECOLOR_NPC)); m_AtlasMarkInfoVectorIterator = m_AtlasNPCInfoVector.begin(); // Add below /* - ATLAS_MARK_INFO [REFACTOR] ------------------------ */ const float halfWidth = static_cast<float>(m_WhiteMark.GetWidth()) * 0.5f; const float halfHeight = static_cast<float>(m_WhiteMark.GetHeight()) * 0.5f; /* ----------------------------------------------------- */ // Search (2x) @@ void CPythonMiniMap::RenderAtlas(float fScreenX, float fScreenY) m_WhiteMark.SetPosition(rAtlasMarkInfo.m_fScreenX, rAtlasMarkInfo.m_fScreenY); // Change (2x) /* - ATLAS_MARK_INFO [REFACTOR] ------------------------ */ m_WhiteMark.SetPosition( rAtlasMarkInfo.m_fScreenX - halfWidth, rAtlasMarkInfo.m_fScreenY - halfHeight ); /* ----------------------------------------------------- */ This fix applies to all clients using the GF Atlas Mark system.
-
Problem Description There has been a small but long-standing issue in the Metin2 client: the game window was opening a few pixels shifted to the right, instead of being perfectly centered. On my system, this offset was around 7 pixels. Not a huge problem, but the “not exactly centered” feeling was clearly noticeable. All fixes shared so far were hard-coded workarounds rather than a proper fix. Today, we'll fix it for good. Before: the window is slightly shifted to the right After: the window is perfectly centered, regardless of taskbar position What Is the Problem? This is not a simple math mistake. On Windows 10/11: GetWindowRect() does not always reflect the exact visual bounds of the window Due to DWM (Desktop Window Manager), the left and right window frames are not symmetrical Because of this, the classic calculation: (screenWidth - windowWidth) / 2 does not always produce a true visual center. What Changed? Along with fixing the centering issue, a few small but important cleanups were made: Fixed the centering logic that caused the client window to open ~7 pixels off to the right The window is now centered based on the actual visual frame seen by the user (Win10/11 DWM-aware) Removed an unnecessary GetWindowRect wrapper that conflicted with the WinAPI function name Completely removed the legacy “another window” reposition logic based on FindWindow This logic was not deterministic on modern Windows It also interfered with correct centering No fixed offsets, magic numbers, or “just move it a bit” hacks were used The window now always opens inside the work area, without overlapping the taskbar or appearing offset How to Client\Source\EterLib\MSWindow.cpp: // Find and erase void CMSWindow::GetWindowRect(RECT* prc) { ::GetWindowRect(m_hWnd, prc); } // Add new helper functions static bool GetVisualWindowRect(HWND hwnd, RECT& outRect) { if (!::GetWindowRect(hwnd, &outRect)) return false; using DwmGetWindowAttributeFn = HRESULT(WINAPI*)(HWND, DWORD, PVOID, DWORD); constexpr DWORD ExtendedFrameBounds = 9; static HMODULE s_dwm = ::LoadLibraryA("dwmapi.dll"); if (!s_dwm) return true; static auto s_getAttr = reinterpret_cast<DwmGetWindowAttributeFn>( ::GetProcAddress(s_dwm, "DwmGetWindowAttribute")); if (!s_getAttr) return true; RECT visual{}; if (SUCCEEDED(s_getAttr(hwnd, ExtendedFrameBounds, &visual, sizeof(visual)))) { outRect = visual; } return true; } static POINT GetCenteredPosition(const RECT& visualRect, const RECT& workArea, const RECT& windowRect) { const int width = visualRect.right - visualRect.left; const int height = visualRect.bottom - visualRect.top; const int dx = visualRect.left - windowRect.left; const int dy = visualRect.top - windowRect.top; POINT pt{}; pt.x = workArea.left + ((workArea.right - workArea.left) - width) / 2 - dx; pt.y = workArea.top + ((workArea.bottom - workArea.top) - height) / 2 - dy; return pt; } // change function void CMSWindow::SetCenterPosition() void CMSWindow::SetCenterPosition() { RECT window{}; RECT visual{}; RECT workArea{}; if (!::GetWindowRect(m_hWnd, &window)) return; visual = window; GetVisualWindowRect(m_hWnd, visual); ::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0); const POINT pos = GetCenteredPosition(visual, workArea, window); SetPosition(pos.x, pos.y); } Client\Source\EterLib\MSWindow.h: // Find and erase void GetWindowRect(RECT* prc); Client\Source\UserInterface\PythonApplication.cpp: // Find and erase bool bAnotherWindow = false; if (FindWindow(NULL, c_szName)) { bAnotherWindow = true; } // Find @@ bool CPythonApplication::Create(PyObject * poSelf, const char* c_szName, int wid AdjustSize(m_pySystem.GetWidth(), m_pySystem.GetHeight()); // Add this underneath CMSWindow::SetCenterPosition(); // Find and erase @@ bool CPythonApplication::Create(PyObject * poSelf, const char* c_szName, int wid if (bAnotherWindow) { RECT rc; GetClientRect(&rc); int windowWidth = rc.right - rc.left; int windowHeight = (rc.bottom - rc.top); CMSApplication::SetPosition(GetScreenWidth() - windowWidth, GetScreenHeight() - 60 - windowHeight); } Client\Source\UserInterface\UserInterface.cpp: // Add to the top of the file #include <shellscalingapi.h> #pragma comment(lib, "Shcore.lib") // Find int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // Add this SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
-
Download Alternative download links → Metin2.Download Pre-Requisites: DirectX 9 DirectX 9Ex has some serious benefits like around 30% less ram usage and the 3D device never getting lost. So no more CTRL+Alt+Del crashes. You can simply paste the diff file here and see the changes needed to be done. You don't need any new libs or anything, it simply works. Here is before and after RAM usage, difference is substantial.
- 5 replies
-
- 270
-
-
-
-
-
-
Shader Manager (Post Process & ...)
Kaptan Yosun replied to Mali's topic in Features & Metin2 Systems
You're legendary! Everything works super smooth. I implemented it to my ImGUI admin panel just like you did. -
For a more in-depth cleanup, you can remove BPP from config and source as it's useless now.
- 1 reply
-
- 1
-
-
Shader Manager (Post Process & ...)
Kaptan Yosun replied to Mali's topic in Features & Metin2 Systems
I'd recommend you to upgrade to Dx9Ex so device never gets lost -
I love such releases
