Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ build/
*build/
bin/
obj/
**/bin/
**/obj/
.vs/
.idea/
.vscode/
Expand All @@ -37,8 +39,14 @@ obj/
*.VC.db
x64/
x86/
**/x64/
**/x86/
Debug/
Release/
Release_codex/
**/Debug/
**/Release/
**/Release_codex/
*.exe
*.dll
*.obj
Expand All @@ -48,6 +56,8 @@ Release/
*.exp
*.iobj
*.ipdb
docs/archive/


# Local bot state
nxrth_config.ini
Expand Down
65 changes: 44 additions & 21 deletions HD/BotEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include "Language.h"
#include "Discord.h"
#include "tesseract_ocr.h"
#include "cpp/src/infra/AhjieCrypto.h"
#include "cpp/src/infra/ActionDebugLog.h"
#include <tesseract/baseapi.h>
#include <leptonica/allheaders.h>
#include "imgui.h"
Expand Down Expand Up @@ -1207,11 +1209,16 @@ static bool TryOpenOccupiedCrateFallbackGrid(int instanceId, int cropMode, int t

for (const auto& slot : kFallbackCrateCenters) {
if (!bot.isRunning) return false;
cv::Mat curScreen = CaptureInstanceScreen(instanceId, kAdbPath, bot.adbSerial);
if (!IsMarketViewLikelyVisible(curScreen, cropMode)) {
AddLog(instanceId, "Shop is not visible. Aborting fallback crate probing.", ImVec4(1.0f, 0.4f, 0.2f, 1.0f));
return false;
}
AdbTap(instanceId, slot.x, slot.y);
std::this_thread::sleep_for(std::chrono::milliseconds(effectiveTapWaitMs));
cv::Mat verifyScreen = CaptureInstanceScreen(instanceId, kAdbPath, bot.adbSerial);
if (IsOccupiedCrateEditPanelVisible(verifyScreen) || IsSalePanelVisible(verifyScreen)) return true;
if (!IsMarketViewLikelyVisible(verifyScreen, cropMode)) return true;
if (!IsMarketViewLikelyVisible(verifyScreen, cropMode)) return false;
}
return false;
}
Expand Down Expand Up @@ -1756,11 +1763,17 @@ bool RunAdbCommand(int instanceId, std::string args) {
std::string serial = g_Bots[instanceId].adbSerial;
if (serial.empty()) return false;

if (args.find("input swipe") != std::string::npos) {
AppendActionDebugLog(instanceId, "SWIPE", "AdbSwipe", args);
}

std::string cmd = "cmd.exe /c \"\"" + kAdbPath + "\" -s " + serial + " " + args + "\"";
return RunCmdHidden(cmd);
}
// TAP FUNCTION TO TAP ON THE SCREEN
void AdbTap(int instanceId, int x, int y) {
std::string detail = "(" + std::to_string(x) + ", " + std::to_string(y) + ")";
AppendActionDebugLog(instanceId, "TAP", "AdbTap", detail);
RunAdbCommand(instanceId, "shell input tap " + std::to_string(x) + " " + std::to_string(y));
}

Expand Down Expand Up @@ -2273,13 +2286,10 @@ void InjectImportantFiles(int instanceId) {

std::thread([instanceId, exeDir, fontFile, zoomFile, minitouchFile]() {
auto decryptNxrthToFile = [&](const std::string& nxPath, const std::string& tempPath) {
std::ifstream inFile(nxPath, std::ios::binary);
std::string encryptedData((std::istreambuf_iterator<char>(inFile)), std::istreambuf_iterator<char>());
inFile.close();

std::string rawData = DecryptXORHex(encryptedData, "NXRTH_NATURE_KEY");
if (rawData.empty()) {
AddLog(instanceId, "Error: Failed to decrypt " + nxPath, ImVec4(1, 0, 0, 1));
std::string rawData;
std::string decryptError;
if (!ahjie::DecryptFileToBytes(nxPath, ahjie::Purpose::Asset, rawData, decryptError)) {
AddLog(instanceId, "Error: Failed to decrypt " + nxPath + " (" + decryptError + ")", ImVec4(1, 0, 0, 1));
return false;
}

Expand Down Expand Up @@ -2706,6 +2716,9 @@ bool AutoDetectTouchDevice(int instanceId) {
void ExecuteDenseGridGesture(int instanceId, int startX, int startY, const std::vector<MatchResult>& fields) {
if (fields.empty()) return;

std::string gestureDetail = "Start=(" + std::to_string(startX) + "," + std::to_string(startY) + "), TargetFields=" + std::to_string(fields.size());
AppendActionDebugLog(instanceId, "SWIPE_GRID", "MinitouchSweep", gestureDetail);

AddLog(instanceId, "[INFO] Executing Sweep...", ImVec4(0.8f, 0.4f, 1.0f, 1.0f));

// 1. FIND FIELD'S BORDER SO THE BOT CAN DRAG IT TO THE CORNER OF THE FIELDS.
Expand Down Expand Up @@ -2779,12 +2792,19 @@ void ExecuteDenseGridGesture(int instanceId, int startX, int startY, const std::
int cx1 = x1 + (int)((tX1 - x1) * t);
int cy1 = y1 + (int)((tY1 - y1) * t);

std::string mCmd = "m 0 " + std::to_string(cx0) + " " + std::to_string(cy0) + " 50\n" +
"m 1 " + std::to_string(cx1) + " " + std::to_string(cy1) + " 50\nc\n";
// Add humanized micro-jitter to drag waypoints
int jx0 = cx0 + (rand() % 5 - 2);
int jy0 = cy0 + (rand() % 5 - 2);
int jx1 = cx1 + (rand() % 5 - 2);
int jy1 = cy1 + (rand() % 5 - 2);

std::string mCmd = "m 0 " + std::to_string(jx0) + " " + std::to_string(jy0) + " 50\n" +
"m 1 " + std::to_string(jx1) + " " + std::to_string(jy1) + " 50\nc\n";
send(sock, mCmd.c_str(), mCmd.length(), 0);


std::this_thread::sleep_for(std::chrono::milliseconds(20));
// Micro-variable step delay (18ms - 23ms)
int stepDelay = 18 + (rand() % 6);
std::this_thread::sleep_for(std::chrono::milliseconds(stepDelay));
}
};

Expand Down Expand Up @@ -3173,18 +3193,11 @@ void RunSalesCycle(int instanceId, int accountIndex, bool isEmergency) {
if (!SmartSleep(g_Intervals.shopEnterWait)) return;

cv::Mat verifyScreen = CaptureInstanceScreen(instanceId, kAdbPath, bot.adbSerial);
if (IsMarketViewLikelyVisible(verifyScreen, bot.testCropMode)) {
if (IsMarketViewLikelyVisible(verifyScreen, bot.testCropMode) || FindBestCrossAny(verifyScreen).found) {
shopOpened = true;
break;
}
if (!FindImage(verifyScreen, shop_templatePath, g_Thresholds.shopThreshold, false, 1.0f, false).found) {
AddLog(instanceId, "Shop icon disappeared after tap. Assuming the roadside shop opened and continuing.", ImVec4(1.0f, 0.85f, 0.2f, 1.0f));
shopOpened = true;
break;
}
else {
AddLog(instanceId, std::string(Tr("Shop click missed (Bug)! Retrying... (")) + std::to_string(tryCount) + "/3)", ImVec4(1, 0.5f, 0, 1));
}
AddLog(instanceId, std::string(Tr("Shop click missed! Retrying... (")) + std::to_string(tryCount) + "/3)", ImVec4(1, 0.5f, 0, 1));
}

if (!shopOpened) {
Expand Down Expand Up @@ -4428,6 +4441,16 @@ static void RunAccountFarmCycle(int instanceId, int accountIndex) {
AddLog(instanceId, Tr("Emergency sales pass finished. Resuming harvest after emergency actions..."), ImVec4(0.8f, 0.4f, 1.0f, 1.0f));
bot.statusText = Tr("Resuming Harvest...");
harvestStatus = TryHarvest();

if (harvestStatus == 2) {
AddLog(instanceId, "SILO STILL FULL! Emergency sales freed 0 items. Setting Silo-Full cooldown to rotate slots.", ImVec4(1.0f, 0.3f, 0.3f, 1.0f));
account.isShopFullStuck = true;
account.lastShopCheckTime = std::chrono::steady_clock::now();
SetFarmFlowState(instanceId, account, FarmFlowState::WaitingForSiloFull, "Silo space unresolved, slot on cooldown");
state = FarmFlowState::CycleComplete;
break;
}

state = FarmFlowState::Planting;
break;

Expand Down
7 changes: 4 additions & 3 deletions HD/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<Project>
<PropertyGroup>
<HaydayVcpkgRoot Condition="'$(HaydayVcpkgRoot)'=='' and '$(VCPKG_ROOT)'!='' and Exists('$(VCPKG_ROOT)\installed\x64-windows\include')">$(VCPKG_ROOT)\</HaydayVcpkgRoot>
<HaydayVcpkgRoot Condition="'$(HaydayVcpkgRoot)'=='' and Exists('D:\vcpkg\installed\x64-windows\include')">D:\vcpkg\</HaydayVcpkgRoot>
<HaydayVcpkgRoot Condition="'$(HaydayVcpkgRoot)'=='' and Exists('E:\vcpkg\installed\x64-windows\include')">E:\vcpkg\</HaydayVcpkgRoot>
<HaydayVcpkgRoot Condition="'$(HaydayVcpkgRoot)'=='' and Exists('D:\01_Apps\DevTools\vcpkg\installed\x64-windows-static-md\include')">D:\01_Apps\DevTools\vcpkg\installed\x64-windows-static-md</HaydayVcpkgRoot>
<HaydayVcpkgRoot Condition="'$(HaydayVcpkgRoot)'=='' and Exists('D:\01_Apps\DevTools\vcpkg\installed\x64-windows\include')">D:\01_Apps\DevTools\vcpkg\installed\x64-windows</HaydayVcpkgRoot>
<HaydayVcpkgRoot Condition="'$(HaydayVcpkgRoot)'=='' and Exists('D:\vcpkg\installed\x64-windows\include')">D:\vcpkg\installed\x64-windows</HaydayVcpkgRoot>
<HaydayVcpkgRoot Condition="'$(HaydayVcpkgRoot)'=='' and Exists('E:\vcpkg\installed\x64-windows\include')">E:\vcpkg\installed\x64-windows</HaydayVcpkgRoot>
</PropertyGroup>
</Project>
4 changes: 3 additions & 1 deletion HD/Premium bot/bot.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
<ClCompile Include="..\rpc_connection.cpp" />
<ClCompile Include="..\serialization.cpp" />
<ClCompile Include="..\tesseract_ocr.cpp" />
<ClCompile Include="..\cpp\src\infra\AhjieCrypto.cpp" />
<ClCompile Include="..\cpp\src\infra\ActionDebugLog.cpp" />
<ClCompile Include="imgui\backends\imgui_impl_glfw.cpp" />
<ClCompile Include="imgui\backends\imgui_impl_opengl3.cpp" />
<ClCompile Include="imgui\imgui.cpp" />
Expand Down Expand Up @@ -201,7 +203,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>glfw3dll.lib;Gdi32.lib;User32.lib;opencv_calib3d4.lib;opencv_core4.lib;opencv_dnn4.lib;opencv_features2d4.lib;opencv_flann4.lib;opencv_highgui4.lib;opencv_imgcodecs4.lib;opencv_imgproc4.lib;opencv_ml4.lib;opencv_objdetect4.lib;opencv_photo4.lib;opencv_stitching4.lib;opencv_video4.lib;opencv_videoio4.lib</AdditionalDependencies>
<AdditionalDependencies>libcurl.lib;archive.lib;libcrypto.lib;libssl.lib;bz2.lib;lz4.lib;glfw3.lib;tesseract55.lib;leptonica-1.87.0.lib;libwebp.lib;libwebpmux.lib;libwebpdecoder.lib;libwebpdemux.lib;libsharpyuv.lib;libpng16.lib;zlib.lib;jpeg.lib;tiff.lib;gif.lib;openjp2.lib;lzma.lib;zstd.lib;Gdi32.lib;User32.lib;Ws2_32.lib;Wldap32.lib;Normaliz.lib;Crypt32.lib;Advapi32.lib;Iphlpapi.lib;Secur32.lib;XmlLite.lib;opencv_calib3d4.lib;opencv_core4.lib;opencv_dnn4.lib;opencv_features2d4.lib;opencv_flann4.lib;opencv_highgui4.lib;opencv_imgcodecs4.lib;opencv_imgproc4.lib;opencv_ml4.lib;opencv_objdetect4.lib;opencv_photo4.lib;opencv_stitching4.lib;opencv_video4.lib;opencv_videoio4.lib</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);$(HaydayVcpkgRoot)\lib;$(ProjectDir)discord-rpc;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
<EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
Expand Down
142 changes: 141 additions & 1 deletion HD/bot_logic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,142 @@ static bool RunCmdHiddenLogic(const std::string& command) {
return true;
}

int g_ScreenshotMode = SCREENSHOT_MODE_WINAPI;

// PrintWindow flag (Windows 8.1+)
#ifndef PW_RENDERFULLCONTENT
#define PW_RENDERFULLCONTENT 0x00000002
#endif

struct WindowSearchCtx {
const char* sub;
HWND found;
};

static BOOL CALLBACK EnumWindowsPartialProc(HWND hwnd, LPARAM lParam) {
if (!IsWindowVisible(hwnd)) return TRUE;
char title[256] = {};
GetWindowTextA(hwnd, title, sizeof(title));
WindowSearchCtx* ctx = (WindowSearchCtx*)lParam;
if (title[0] != '\0' && ctx->sub && strstr(title, ctx->sub) != nullptr) {
ctx->found = hwnd;
return FALSE;
}
return TRUE;
}

static HWND FindWindowPartial(const char* windowTitle) {
if (!windowTitle || windowTitle[0] == '\0') return NULL;
HWND hwnd = FindWindowA(NULL, windowTitle);
if (hwnd && IsWindow(hwnd)) return hwnd;

WindowSearchCtx ctx{ windowTitle, NULL };
EnumWindows(EnumWindowsPartialProc, (LPARAM)&ctx);
return ctx.found;
}

// --- WINDOWS API (GDI) FAST SCREENSHOT CAPTURE ---
static cv::Mat CaptureWindowGDI(const char* windowTitle, int targetW, int targetH) {
if (!windowTitle || windowTitle[0] == '\0' || targetW <= 0 || targetH <= 0)
return cv::Mat();

HWND hwnd = FindWindowPartial(windowTitle);
if (!hwnd || !IsWindow(hwnd)) return cv::Mat();

RECT wr;
if (!GetWindowRect(hwnd, &wr)) return cv::Mat();
int fullW = wr.right - wr.left;
int fullH = wr.bottom - wr.top;
if (fullW <= 0 || fullH <= 0) return cv::Mat();

HDC hdcScreen = GetDC(NULL);
HDC hdcMem = CreateCompatibleDC(hdcScreen);
HBITMAP hbm = CreateCompatibleBitmap(hdcScreen, fullW, fullH);
HGDIOBJ oldObj = SelectObject(hdcMem, hbm);

BOOL ok = PrintWindow(hwnd, hdcMem, PW_RENDERFULLCONTENT);
if (!ok) ok = PrintWindow(hwnd, hdcMem, 0);

SelectObject(hdcMem, oldObj);

cv::Mat full;
if (ok) {
BITMAPINFOHEADER bi = {};
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = fullW;
bi.biHeight = -fullH; // top-down
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;

cv::Mat bgra(fullH, fullW, CV_8UC4);
if (GetDIBits(hdcScreen, hbm, 0, fullH, bgra.data, (BITMAPINFO*)&bi, DIB_RGB_COLORS)) {
cv::cvtColor(bgra, full, cv::COLOR_BGRA2BGR);
}
}

DeleteObject(hbm);
DeleteDC(hdcMem);
ReleaseDC(NULL, hdcScreen);

if (full.empty()) return cv::Mat();

// Client area crop (strip title bar & borders)
RECT cr;
POINT tl = { 0, 0 };
if (GetClientRect(hwnd, &cr) && ClientToScreen(hwnd, &tl)) {
int offX = tl.x - wr.left;
int offY = tl.y - wr.top;
int cw = cr.right - cr.left;
int ch = cr.bottom - cr.top;
if (cw > 0 && ch > 0 && offX >= 0 && offY >= 0 &&
offX + cw <= full.cols && offY + ch <= full.rows) {
full = full(cv::Rect(offX, offY, cw, ch)).clone();
}
}

// Render area crop (strip emulator sidebar toolbar)
double targetAR = (double)targetW / (double)targetH;
int cw = full.cols, ch = full.rows;
int renderW, renderH;
int fitW = (int)(ch * targetAR + 0.5);
if (fitW <= cw) {
renderW = fitW;
renderH = ch;
}
else {
renderW = cw;
renderH = (int)(cw / targetAR + 0.5);
}
if (renderW > 0 && renderH > 0 && renderW <= full.cols && renderH <= full.rows) {
full = full(cv::Rect(0, 0, renderW, renderH));
}

// Reject black frames (fall back to ADB)
cv::Scalar m = cv::mean(full);
if (m[0] + m[1] + m[2] < 3.0) return cv::Mat();

cv::Mat out;
cv::resize(full, out, cv::Size(targetW, targetH), 0, 0, cv::INTER_AREA);
return out;
}

static constexpr int kMaxInstanceCount = 6;
static int g_RefCapW[kMaxInstanceCount] = { 0 };
static int g_RefCapH[kMaxInstanceCount] = { 0 };

// SCREEN CAPTURING
cv::Mat CaptureInstanceScreen(int instanceId, const std::string& adbPath, const std::string& serial) {
if (g_ScreenshotMode == SCREENSHOT_MODE_WINAPI &&
instanceId >= 0 && instanceId < kMaxInstanceCount) {
int tw = g_RefCapW[instanceId];
int th = g_RefCapH[instanceId];
if (tw > 0 && th > 0) {
cv::Mat win = CaptureWindowGDI(g_Bots[instanceId].vmName, tw, th);
if (!win.empty()) return win;
}
}

std::string tempFile = "C:\\Users\\Public\\adb_screen_" + std::to_string(instanceId) + ".png";
int maxRetries = 2;
cv::Mat img;
Expand All @@ -110,7 +244,13 @@ cv::Mat CaptureInstanceScreen(int instanceId, const std::string& adbPath, const
if (RunCmdHiddenLogic(cmd)) {
if (WaitForValidFile(tempFile)) {
img = cv::imread(tempFile);
if (!img.empty()) return img;
if (!img.empty()) {
if (instanceId >= 0 && instanceId < kMaxInstanceCount) {
g_RefCapW[instanceId] = img.cols;
g_RefCapH[instanceId] = img.rows;
}
return img;
}
}
}
// RETRY IF FAILED
Expand Down
15 changes: 14 additions & 1 deletion HD/bot_logic.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,19 +362,31 @@ struct TemplateThresholds {
float siloFullCrossThreshold = 0.70f;
};

constexpr int SCREENSHOT_MODE_WINAPI = 0;
constexpr int SCREENSHOT_MODE_ADB = 1;
extern int g_ScreenshotMode;

struct IntervalSettings {
int gameLoadWait = 22;
int afterHarvestWait = 2800;
int afterPlantWait = 2600;
int fieldTapWait = 250;
int menuCloseWait = 500;
int tapResponseWait = 400;
int pageLoadWait = 1000;
int shopSearchWait = 500;
int shopEnterWait = 2000;
int crateOpenWait = 600;
int crateClickWait = 800;
int nextAccountWait = 2000;
int coinCollectWait = 700;
int productSelectWait = 500;
int createSaleWait = 1000;
int saleConfirmWait = 500;
int siloBarnWait = 1500;
int accountLoadWait = 2000;
bool autoZoomOutAfterMailbox = false;
int mailboxZoomDelayMs = 5000;

};


Expand All @@ -401,3 +413,4 @@ std::vector<MatchResult> FindEmptyFields(const cv::Mat& screen, bool isRecheck =

std::string EncryptXORHex(const std::string& text, const std::string& key = "ISpentDaysForThisApp");
std::string DecryptXORHex(const std::string& hexStr, const std::string& key = "ISpentDaysForThisApp");

Loading
Loading