- Katılım
- 6 Mayıs 2022
- Konular
- 48,280
- Mesajlar
- 48,590
- Tepkime puanı
- 75
- M2 Yaşı
- 3 yıl 11 ay 10 gün
- Trophy Puan
- 48
- M2 Yang
- 488,769
[C++] Metin2 Client Window Centering Bug (Win10 / Win11)
Gerçek Sebep ve Kalıcı Çözüm
Gerçek Sebep ve Kalıcı Çözüm
Metin2 client’ında uzun zamandır var olan küçük ama fark edilen bir problem vardı.
Oyun penceresi açıldığında yatay eksende tam ortaya oturmuyordu.
Benim sistemimde bu fark yaklaşık 7 piksel civarındaydı.
Büyük bir şey değil ama “tam ortada değil” hissi net olarak vardı.
Before: pencere yatayda hafif sağa kayık
After: taskbar pozisyonu fark etmeksizin tam ortalanmış
Bu sorun basit bir matematik hatası değil.
Win10 / Win11 üzerinde:
- <li data-xf-list-type="ul"> GetWindowRect() pencerenin gerçek görsel sınırlarını birebir yansıtmıyor <li data-xf-list-type="ul"> DWM (Desktop Window Manager) nedeniyle pencerenin sol ve sağ çerçeveleri simetrik değil
Bu yüzden klasik olarak kullanılan:
Kod:
(screenWidth - windowWidth) / 2
Bu çalışmayla birlikte birkaç küçük ama önemli temizlik de yapıldı.
- <li data-xf-list-type="ul"> Client penceresinin yatayda yaklaşık 7 piksel sağa kayık açılmasına sebep olan merkezleme mantığı düzeltildi <li data-xf-list-type="ul"> Pencere artık kullanıcının gerçekten gördüğü frame’e göre ortalanıyor (Win10 / Win11 DWM uyumlu) <li data-xf-list-type="ul"> GetWindowRect için yazılmış, WinAPI ismiyle çakışan gereksiz wrapper fonksiyon kaldırıldı <li data-xf-list-type="ul"> FindWindow ile pencere başlığına bakarak yapılan “another window” reposition mantığı tamamen kaldırıldı <li data-xf-list-type="ul"> Bu kod modern Windows sürümlerinde deterministik çalışmıyordu ve merkezlemeyi bozuyordu <li data-xf-list-type="ul"> Sabit offset, magic number veya “biraz sola kaydır” tarzı hack’ler kullanılmadı <li data-xf-list-type="ul"> Pencere artık her zaman work area içinde, taskbar’a taşmadan ve kayık olmadan açılıyor
Aşağıdaki video, yapılan değişiklikten sonraki sonucu gösteriyor:
Uygulama kısmı:
Client\\Source\\EterLib\\MSWindow.cpp dosyasında aşağıdaki wrapper fonksiyonu bulun ve silin:
Kod:
void CMSWindow::GetWindowRect(RECT* prc) { ::GetWindowRect(m_hWnd, prc); }
Ardından DWM uyumlu yeni yardımcı fonksiyonları ekleyin:
Kod:
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; }
CMSWindow::SetCenterPosition() fonksiyonunu aşağıdaki şekilde değiştirin:
Kod:
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 dosyasında aşağıdaki tanımı silin:
Kod:
void GetWindowRect(RECT* prc);
Client\\Source\\UserInterface\\PythonApplication.cpp içinde aşağıdaki kodu bulun ve kaldırın:
Kod:
bool bAnotherWindow = false; if (FindWindow(NULL, c_szName)) { bAnotherWindow = true; }
AdjustSize çağrısının hemen altına şunu ekleyin:
Kod:
CMSWindow::SetCenterPosition();
Ve aşağıdaki bloğu tamamen silin:
Kod:
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); }
Bu değişiklikten sonra pencere artık piksel şaşması olmadan, taskbar konumundan bağımsız şekilde tam ortaya oturur.
Herhangi bir sabit offset veya geçici çözüm kullanılmaz, davranış tamamen deterministiktir.
<h4>Kaptan Yosun'dan alıntıdır. İyi kullanımlar dilerim.</h4>
Metin2 Client Window Centering Bugu Nedir?
Metin2 özel sunucularında geliştirme yaparken karşılaşılan yaygın sorunlardan birisi client window centering bug'dır. Bu hata, oyuncu arayüzünün başlatılması sırasında pencerenin ekranın merkezinde doğru şekilde konumlandırılmaması durumunda ortaya çıkar. Özellikle fullscreen modda oyun başlatıldığında veya farklı çözünürlük ayarları değiştirildiğinde bu hata daha sık görülmektedir. Bu yazıda, bu hatayı tanımlayacağız, neden oluştuğunu anlatacağız ve çözüm önerileri sunacağız.
Hatanın Neden Kaynağı
Bu hata genellikle uiscript dosyalarındaki pencere pozisyonlamasıyla ilgilidir. Metin2 client tarafında UI elemanlarının konumlandırılması, C++ ve Python tabanlı sistemlerle sağlanır. Özellikle py root ve py gui sistemleri üzerinden yapılan arayüz değişikliklerinde, pencere boyutları ve konumlar sabit değerlerle tanımlanmaya çalışıldığında merkezi konumlandırma işlemi başarısız olabilir. Bu da oyuncunun ekranının sol üst köşede kalmasına veya tam olarak ortalanmamasına neden olur.
Çözüm Yöntemleri
Öncelikle uiscript dosyalarında bulunan window sınıflarında kullanılan pozisyon değerlerinin dinamik olarak belirlenmesi gerekir. Bunun için ekran çözünürlüğüne göre orantılı konumlandırma yapılması önerilir. Örneğin:
Kod:
window.SetPosition((SCREEN_WIDTH - window.GetWidth()) / 2, (SCREEN_HEIGHT - window.GetHeight()) / 2)
Bu kod parçası, pencereyi ekranın tam ortasına yerleştirir. Ayrıca C++ seviyesinde game core üzerinde yapılan düzenlemelerle, pencere başlatma sırasında ekran boyutları doğru şekilde algılanmalıdır. Eğer çözünürlük değişikliklerinde bu değerler güncellenmiyorsa, bu durumda client src üzerinde uygun callback fonksiyonları tanımlanarak, çözünürlüğe göre yeniden konumlandırma yapılmalıdır.
Python GUI ve Py Root Üzerinde Uygulama
Metin2 client tarafında UI geliştirmeleri genellikle Python GUI sistemleri ile yapılır. Bu sistemlerde py root dosyaları, arayüz elemanlarını kontrol eder. Pencere konumlandırma işlemleri bu dosyalar üzerinde tanımlanmalıdır. Örneğin bir systemdialog.py dosyasında şu şekilde bir fonksiyon tanımlanabilir:
Kod:
def center_window(self):[BR][/BR] screen_width = wndMgr.GetScreenWidth()[BR][/BR] screen_height = wndMgr.GetScreenHeight()[BR][/BR] window_width = self.GetWidth()[BR][/BR] window_height = self.GetHeight()[BR][/BR] self.SetPosition((screen_width - window_width) // 2, (screen_height - window_height) // 2)
Bu yöntem, arayüz elemanlarının her çözünürlükte doğru şekilde ortalanmasını sağlar. Aynı zamanda pack dosyaları üzerinden UI değişiklikleri yapıldığında, bu tür konumlandırmaların doğruluğu korunmalıdır.
Yanlış Yaklaşımlar
Bazı geliştiriciler, sabit koordinatlar kullanarak pencere konumunu belirlemeye çalışırlar. Bu yaklaşım, farklı çözünürlüklerde uyumsuzluklara yol açar. Örneğin, 1920x1080 çözünürlükte çalışan bir pencere, 1366x768 gibi daha küçük bir ekranda taşabilir veya yanlış konumda görünebilir. Bu nedenle, sabit değerler yerine çözünürlüğe göre orantılı hesaplamalar yapılmalıdır.
Sonuç
Metin2 client window centering bug gibi küçük görünümlü fakat kullanıcı deneyimini ciddi şekilde etkileyebilecek hatalar, doğru konfigürasyon ve uygun kodlama ile kolayca çözülebilir. Geliştiricilerin özellikle uiscript, py root, client src ve py gui sistemlerinde dikkatli hareket etmesi, bu tür hataların önlenmesinde kilit rol oynar. Metin2Lobby olarak, bu tür gelişmiş teknik konulara odaklanarak Metin2 özel sunucu geliştiricilerine destek olmaya devam ediyoruz.
What is the Metin2 Client Window Centering Bug?
One of the common issues encountered during development on Metin2 private servers is the client window centering bug. This error occurs when the user interface fails to position itself correctly at the center of the screen upon initialization. It is especially noticeable when the game is launched in fullscreen mode or when different resolution settings are altered. In this article, we will define this issue, explain why it occurs, and provide potential solutions.
Root Cause of the Issue
This bug typically stems from improper window positioning within the uiscript files. The UI elements in Metin2 client are managed through C++ and Python-based systems. When UI modifications are made via py root and py gui systems, and window sizes and positions are hardcoded instead of dynamically calculated, the centering process may fail. This leads to the game window appearing in the top-left corner or not being centered properly on the screen.
Solution Approaches
Firstly, the position values used in the window classes within uiscript files should be determined dynamically. It is recommended to use calculations based on the screen resolution. For example:
Kod:
window.SetPosition((SCREEN_WIDTH - window.GetWidth()) / 2, (SCREEN_HEIGHT - window.GetHeight()) / 2)
This code snippet centers the window on the screen. Additionally, at the C++ level within the game core, screen dimensions must be accurately detected during window initialization. If these values are not updated during resolution changes, appropriate callback functions should be defined in the client src to reposition the window accordingly.
Implementation in Python GUI and Py Root
UI improvements in the Metin2 client are usually handled through Python GUI systems. These systems control UI components via py root files. Window positioning should be defined in these files. For instance, in a systemdialog.py file, you could define a function like so:
Kod:
def center_window(self):[BR][/BR] screen_width = wndMgr.GetScreenWidth()[BR][/BR] screen_height = wndMgr.GetScreenHeight()[BR][/BR] window_width = self.GetWidth()[BR][/BR] window_height = self.GetHeight()[BR][/BR] self.SetPosition((screen_width - window_width) // 2, (screen_height - window_height) // 2)
This approach ensures that UI elements are centered correctly across all resolutions. Moreover, when UI changes are made through pack files, such positioning calculations must remain accurate.
Incorrect Approaches
Some developers attempt to set window positions using fixed coordinates. This approach causes inconsistencies on different resolutions. For example, a window that works on 1920x1080 may overflow or appear incorrectly on a smaller resolution like 1366x768. Therefore, proportional calculations based on resolution should be preferred over hardcoded values.
Conclusion
Issues like the Metin2 client window centering bug, although seemingly minor, can significantly impact user experience. They can be easily resolved with proper configuration and correct coding practices. Developers need to pay close attention to uiscript, py root, client src, and py gui systems to prevent such errors. At Metin2Lobby, we continue to support Metin2 private server developers by focusing on such advanced technical topics.
