GolemHelper/GolemHelper/Automation/CoordinateUtils.cpp
Azrub d035d14587 Release v1.7.0.0
New Features:

- Added Coordinate Calibration - manually calibrate click positions for unsupported resolutions, UI scales, or custom Windows DPI settings via addon options
- Calibration values are saved persistently and applied globally to all click sequences

UI Improvements:

- Moved "Current template" indicator inside the Templates tab - also resolves window stretching on certain resolutions
- Added hint below delay settings to suggest calibration if clicks miss

Technical Changes:

- Fixed implicit size_t to int conversion warning in template list rendering
2026-04-02 00:53:28 +02:00

253 lines
No EOL
9.4 KiB
C++

#include <Windows.h>
#include <string>
#include "CoordinateUtils.h"
#include "../Common/Globals.h"
#include "../Config/ConfigManager.h"
void CoordinateUtils::GetScaledCoordinates(int baseX, int baseY, int* scaledX, int* scaledY) {
if (!g_api) return;
if (g_state.hasCalibration) {
*scaledX = (int)(baseX * g_state.calibratedScaleX);
*scaledY = (int)(baseY * g_state.calibratedScaleY);
return;
}
if (g_nexusLink && g_nexusLink->Width > 0 && g_nexusLink->Height > 0) {
float uiScale = g_nexusLink->Scaling;
float dpiScaleX, dpiScaleY;
// Ultrawide 5120x1440
if (g_nexusLink->Width == 5120 && g_nexusLink->Height == 1440) {
if (uiScale >= 0.89f && uiScale <= 0.91f) {
dpiScaleX = 2.814f;
dpiScaleY = 0.888f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "ULTRAWIDE 5120x1440: APPLIED SMALL UI OFFSET");
}
else if (uiScale >= 1.09f && uiScale <= 1.15f) {
dpiScaleX = 2.746f;
dpiScaleY = 1.104f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "ULTRAWIDE 5120x1440: APPLIED LARGE UI OFFSET");
}
else if (uiScale >= 1.21f && uiScale <= 1.25f) {
dpiScaleX = 2.713f;
dpiScaleY = 1.208f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "ULTRAWIDE 5120x1440: APPLIED LARGER UI OFFSET");
}
else {
dpiScaleX = 2.779f;
dpiScaleY = 1.000f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "ULTRAWIDE 5120x1440: APPLIED NORMAL UI OFFSET");
}
}
// Ultrawide 3440x1440
else if (g_nexusLink->Width == 3440 && g_nexusLink->Height == 1440) {
if (uiScale >= 0.89f && uiScale <= 0.91f) {
dpiScaleX = 1.810f;
dpiScaleY = 0.892f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "ULTRAWIDE 3440x1440: APPLIED SMALL UI OFFSET");
}
else if (uiScale >= 1.09f && uiScale <= 1.15f) {
dpiScaleX = 1.741f;
dpiScaleY = 1.104f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "ULTRAWIDE 3440x1440: APPLIED LARGE UI OFFSET");
}
else if (uiScale >= 1.21f && uiScale <= 1.25f) {
dpiScaleX = 1.708f;
dpiScaleY = 1.212f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "ULTRAWIDE 3440x1440: APPLIED LARGER UI OFFSET");
}
else {
dpiScaleX = 1.773f;
dpiScaleY = 0.992f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "ULTRAWIDE 3440x1440: APPLIED NORMAL UI OFFSET");
}
}
else if (g_nexusLink->Width == 3840 && g_nexusLink->Height == 2160) {
if (uiScale >= 0.89f && uiScale <= 0.91f) {
dpiScaleX = 2.052f;
dpiScaleY = 0.908f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "4K 3840x2160: APPLIED SMALL UI OFFSET");
}
else if (uiScale >= 1.09f && uiScale <= 1.15f) {
dpiScaleX = 1.985f;
dpiScaleY = 1.130f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "4K 3840x2160: APPLIED LARGE UI OFFSET");
}
else if (uiScale >= 1.21f && uiScale <= 1.25f) {
dpiScaleX = 1.952f;
dpiScaleY = 1.233f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "4K 3840x2160: APPLIED LARGER UI OFFSET");
}
else {
dpiScaleX = 2.0f;
dpiScaleY = 1.0f;
g_api->Log(ELogLevel_INFO, "GolemHelper", "4K 3840x2160: APPLIED NORMAL UI OFFSET");
}
}
else {
dpiScaleX = (float)g_nexusLink->Width / 1920.0f;
dpiScaleY = 1.0f;
char normalBuffer[150];
sprintf_s(normalBuffer, "NORMAL MONITOR: Width=%d, Height=%d, scaleX=%.3f",
g_nexusLink->Width, g_nexusLink->Height, dpiScaleX);
g_api->Log(ELogLevel_INFO, "GolemHelper", normalBuffer);
}
int scaledForResolutionX = (int)(baseX * dpiScaleX);
int scaledForResolutionY = (int)(baseY * dpiScaleY);
int finalX = scaledForResolutionX;
int finalY = scaledForResolutionY;
if (!(g_nexusLink->Width == 5120 && g_nexusLink->Height == 1440) &&
!(g_nexusLink->Width == 3440 && g_nexusLink->Height == 1440) &&
!(g_nexusLink->Width == 3840 && g_nexusLink->Height == 2160)) {
if (uiScale >= 0.89f && uiScale <= 0.91f) {
finalX = scaledForResolutionX - (int)(scaledForResolutionX * 0.029f);
finalY = scaledForResolutionY - (int)(scaledForResolutionY * 0.103f);
g_api->Log(ELogLevel_INFO, "GolemHelper", "APPLIED SMALL UI OFFSET");
}
else if (uiScale >= 1.09f && uiScale <= 1.15f) {
finalX = scaledForResolutionX - (int)(scaledForResolutionX * 0.053f);
finalY = scaledForResolutionY + (int)(scaledForResolutionY * 0.095f);
g_api->Log(ELogLevel_INFO, "GolemHelper", "APPLIED LARGE UI OFFSET");
}
else if (uiScale >= 1.21f && uiScale <= 1.25f) {
finalX = scaledForResolutionX - (int)(scaledForResolutionX * 0.097f);
finalY = scaledForResolutionY + (int)(scaledForResolutionY * 0.206f);
}
}
*scaledX = finalX;
*scaledY = finalY;
}
else {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "GetScaledCoordinates - Nexus data not available");
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
float dpiScale = (float)screenWidth / 1920.0f;
*scaledX = (int)(baseX * dpiScale);
*scaledY = baseY;
}
}
void CoordinateUtils::DebugMousePosition() {
if (!g_api) return;
POINT mousePos;
GetCursorPos(&mousePos);
if (g_nexusLink && g_nexusLink->Width > 0 && g_nexusLink->Height > 0) {
float uiScale = g_nexusLink->Scaling;
float dpiScale = (float)g_nexusLink->Width / 1920.0f;
float finalScaleX = uiScale * dpiScale;
int baseX = (int)(mousePos.x / finalScaleX);
int baseY = mousePos.y;
g_state.debugCounter++;
char buffer[450];
sprintf_s(buffer, "=== DEBUG #%d === Resolution: %dx%d | Mouse: %d,%d | Base coords: %d,%d | Interface Size: %.2f | DPI Scale: %.3f | Final ScaleX: %.3f",
g_state.debugCounter, g_nexusLink->Width, g_nexusLink->Height,
mousePos.x, mousePos.y, baseX, baseY, uiScale, dpiScale, finalScaleX);
g_api->Log(ELogLevel_INFO, "GolemHelper", buffer);
}
else {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Cannot debug - Nexus data not available");
}
}
void CoordinateUtils::ClickAtScaled(int baseX, int baseY, int delay) {
if (g_mumbleData && !g_mumbleData->Context.IsGameFocused) {
if (g_api) {
g_api->Log(ELogLevel_WARNING, "GolemHelper", "Sequence stopped - Game lost focus");
}
return;
}
HWND gameWindow = GetForegroundWindow();
if (!gameWindow) return;
int scaledX, scaledY;
GetScaledCoordinates(baseX, baseY, &scaledX, &scaledY);
LPARAM lParam = MAKELPARAM(scaledX, scaledY);
SendMessage(gameWindow, WM_LBUTTONDOWN, MK_LBUTTON, lParam);
Sleep(10);
SendMessage(gameWindow, WM_LBUTTONUP, 0, lParam);
Sleep(delay);
}
void CoordinateUtils::StartCalibration() {
g_state.calibrationMode = true;
g_state.showUI = false;
if (g_api) {
g_api->Log(ELogLevel_INFO, "GolemHelper",
"Calibration started - interact with the Boon Console and click 'Adjust Self'");
}
}
void CoordinateUtils::CaptureCalibrationPoint() {
POINT mousePos;
GetCursorPos(&mousePos);
const float REF_BASE_X = 830.0f;
const float REF_BASE_Y = 262.0f;
g_state.calibratedScaleX = mousePos.x / REF_BASE_X;
g_state.calibratedScaleY = mousePos.y / REF_BASE_Y;
g_state.hasCalibration = true;
g_state.calibrationMode = false;
ConfigManager::SaveCustomDelaySettings();
if (g_api) {
char buffer[256];
sprintf_s(buffer,
"Calibration saved: click=(%ld, %ld) scaleX=%.4f scaleY=%.4f",
mousePos.x, mousePos.y,
g_state.calibratedScaleX, g_state.calibratedScaleY);
g_api->Log(ELogLevel_INFO, "GolemHelper", buffer);
g_api->UI.SendAlert("Calibration saved!");
}
}
void CoordinateUtils::ResetCalibration() {
g_state.hasCalibration = false;
g_state.calibrationMode = false;
g_state.calibratedScaleX = 1.0f;
g_state.calibratedScaleY = 1.0f;
ConfigManager::SaveCustomDelaySettings();
if (g_api) {
g_api->Log(ELogLevel_INFO, "GolemHelper", "Calibration reset - back to auto-scaling");
g_api->UI.SendAlert("Calibration reset to default");
}
}
void CoordinateUtils::UpdateCalibrationCapture() {
if (!g_state.calibrationMode) return;
if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) {
g_state.calibrationMode = false;
if (g_api) g_api->UI.SendAlert("Calibration cancelled");
return;
}
static bool s_wasPressed = false;
bool isPressed = (GetAsyncKeyState(VK_LBUTTON) & 0x8000) != 0;
if (isPressed && !s_wasPressed) {
if (g_mumbleData && g_mumbleData->Context.IsGameFocused) {
CaptureCalibrationPoint();
}
}
s_wasPressed = isPressed;
}