GDTheuTrich

somegdaicode

Apr 22nd, 2023
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.32 KB | None | 0 0
  1. #include "HAPIH.h"
  2. #include <windows.h>
  3. #include <iostream>
  4. #include <fstream>
  5. #include <cmath>
  6. #include <random>
  7. #include <set>
  8. #include <unordered_map>
  9. #include <vector>
  10. #include <chrono>
  11. #include <string>
  12. #include <cstring>
  13. #include <algorithm>
  14. #include <list>
  15. #undef max
  16.  
  17. double MAX_ODDS = 4.0;
  18. int FPS = 60;
  19. int MAX_ATTEMPTS = 10;
  20. #define ODDS ((bestLastJump == 0.0 ? (bestFitness / 2.0) : bestLastJump) / bestFitness) / (100.0 / MAX_ODDS) + 0.0001
  21.  
  22. /*
  23. * We can now read the mode, as well as some other stuff, with the offset GeometryDash.exe + 3222D0 + 164 + 224 + 638.
  24. * This is an "array" of booleans with the contents:
  25. * [0]: Is ship?
  26. * [1]: Is UFO? (interesting that it's earlier than ball, since UFO is newer)
  27. * [2]: Is ball?
  28. * [3]: Is wave?
  29. * [4]: Is robot?
  30. * [5]: Is spider?
  31. * [6]: Is upside-down?
  32. * [7]: Is dead?
  33. */
  34.  
  35. enum class Mode {
  36. cube,
  37. ship,
  38. ball,
  39. ufo,
  40. wave,
  41. robot,
  42. spider,
  43. unknown
  44. };
  45.  
  46. const char * modeNames[] = {
  47. "cube",
  48. "ship",
  49. "ball",
  50. "ufo",
  51. "wave",
  52. "robot",
  53. "spider",
  54. "unknown"
  55. };
  56.  
  57. bool modeFlying[] = {
  58. false,
  59. true,
  60. false,
  61. false,
  62. true,
  63. true,
  64. false,
  65. false
  66. };
  67.  
  68. bool isDead = false;
  69. Mode toMode(uint32_t hi, uint32_t lo) {
  70. isDead = hi & 0x1000000;
  71. hi &= 0xFFFF;
  72. if (hi == 0) {
  73. if (lo == 0) return Mode::cube;
  74. else if (lo == 0x1) return Mode::ship;
  75. else if (lo == 0x100) return Mode::ufo;
  76. else if (lo == 0x10000) return Mode::ball;
  77. else if (lo == 0x1000000) return Mode::wave;
  78. else return Mode::unknown;
  79. } else if (hi == 0x1) return Mode::robot;
  80. else if (hi == 0x100) return Mode::spider;
  81. else return Mode::unknown;
  82. }
  83.  
  84. const std::unordered_map<std::string, double> oddsForAllMaps = {
  85. {"StereoMadness", 3.0},
  86. {"BackOnTrack", 4.0},
  87. {"Polargeist", 4.0},
  88. {"DryOut", 4.0},
  89. {"BaseAfterBase", 4.0},
  90. {"CantLetGo", 4.0},
  91. {"Jumper", 4.0},
  92. {"TimeMachine", 4.5},
  93. {"Cycles", 4.0},
  94. {"xStep", 5.0},
  95. {"Clutterfunk", 5.0},
  96. {"TheoryOfEverything", 5.0},
  97. {"ElectromanAdventures", 5.0},
  98. {"Clubstep", 6.0},
  99. {"Electrodynamix", 6.0},
  100. {"HexagonForce", 5.0},
  101. {"BlastProcessing", 4.0},
  102. {"TheoryOfEverything2", 6.0},
  103. {"GeometricalDominator", 5.0},
  104. {"Deadlocked", 6.0},
  105. {"Fingerdash", 5.0}
  106. };
  107.  
  108. double bestFitness = 1;
  109. double bestFitnessR = 0;
  110. std::list<uint32_t> bestJumps;
  111. double bestLastJump = 1;
  112. int failCount = 0;
  113. float lastX = 0;
  114. std::ofstream out;
  115. bool saving = false;
  116. bool isDown = false;
  117. Mode mode = Mode::cube;
  118.  
  119. void jump(const HackIH& GD, HWND window, bool state) {
  120. /*GD.Write<bool>({GD.BaseAddress, 0x3222D0, 0x164, 0x224, 0x611}, state);
  121. GD.Write<bool>({GD.BaseAddress, 0x3222D0, 0x164, 0x224, 0x612}, state);
  122. if (!state) GD.Write<bool>({GD.BaseAddress, 0x3222D0, 0x164, 0x224, 0x641}, state);
  123. if (GD.Read<bool>({GD.BaseAddress, 0x3222D0, 0x164, 0x228, 0x685}) || !state) {
  124. GD.Write<bool>({GD.BaseAddress, 0x3222D0, 0x164, 0x228, 0x611}, state);
  125. GD.Write<bool>({GD.BaseAddress, 0x3222D0, 0x164, 0x228, 0x612}, state);
  126. if (!state) GD.Write<bool>({GD.BaseAddress, 0x3222D0, 0x164, 0x228, 0x641}, state);
  127. }*/
  128. if (state) PostMessage(window, WM_LBUTTONDOWN, MK_LBUTTON, 0);
  129. else PostMessage(window, WM_LBUTTONUP, 0, 0);
  130. Sleep(75);
  131. }
  132.  
  133. void saveLevel(const char * argv[]) {
  134. if (!saving) return;
  135. bool loop = false;
  136. do {
  137. out.open(argv[2], std::ios_base::binary);
  138. out.write((char*)&bestFitness, sizeof(double));
  139. out.write((char*)&bestLastJump, sizeof(double));
  140. out.write(argv[1], strlen(argv[1]) + 1);
  141. for (uint32_t i : bestJumps) out.write((char*)&i, 4);
  142. out.put(0); out.put(0); out.put(0); out.put(0);
  143. long pos = out.tellp();
  144. out.close();
  145. // Rewrite the file if it gets corrupted
  146. if (pos < sizeof(double) * 2 + strlen(argv[1]) + 1 + bestJumps.size() * 4 + 4) loop = true;
  147. } while (loop);
  148. }
  149.  
  150. int main(int argc, const char * argv[]) {
  151. if (argc > 1) {
  152. if (std::string(argv[1]) == "--help" || std::string(argv[1]) == "-h" || std::string(argv[1]) == "-?") {
  153. std::cout << "DashBot is a simple AI designed to beat Geometry Dash levels. This version works with Geometry Dash 2.11.\nUsage: " << argv[0] << " [level name|jump speed] [save.dbj]\nType \"" << argv[0] << " list\" to list level names.\n";
  154. return 0;
  155. } else if (std::string(argv[1]) == "list") {
  156. std::cout << "List of known level names: ";
  157. for (std::pair<std::string, double> p : oddsForAllMaps) std::cout << p.first << ", ";
  158. std::cout << "\nTo use DashBot with another level, you can supply the jump speed (defaults to 4.0). A higher value will cause DashBot to jump more often. Use a higher value for faster/harder levels, and a lower value for slower levels.\n";
  159. return 0;
  160. } else if (oddsForAllMaps.find(argv[1]) != oddsForAllMaps.end()) {
  161. MAX_ODDS = oddsForAllMaps.at(argv[1]) * (60.0 / FPS);
  162. } else if (std::all_of(argv[1], argv[1] + strlen(argv[1]), [](char c)->bool{return isdigit(c) || c == '.';})) {
  163. MAX_ODDS = atof(argv[1]);
  164. } else {
  165. std::cerr << "Usage: " << argv[0] << " [level name|jump speed] [save.dbj] [fps]\nType \"" << argv[0] << " list\" to list level names\n";
  166. return 1;
  167. }
  168. }
  169. std::cout << "DashBot v3.2\nBased on Pizzabot-v4 by Pizzaroot\n";
  170. if (argc > 2) {
  171. saving = true;
  172. // file format:
  173. // double - bestFitness
  174. // double - bestLastJump
  175. // const char * - portal type
  176. // uint32_t* - bestJumps
  177. // uint32_t - 0
  178. std::ifstream in(argv[2], std::ios_base::binary);
  179. if (in.is_open()) {
  180. in.read((char*)&bestFitness, sizeof(double));
  181. in.read((char*)&bestLastJump, sizeof(double));
  182. while (in.get()) ; // ignore level type, we already know that
  183. uint32_t n = 0;
  184. while (!in.eof()) {
  185. in.read((char*)&n, 4);
  186. if (!n) break;
  187. bestJumps.push_back(n);
  188. }
  189. in.close();
  190. } else std::cerr << "Could not open input file, ignore this if you're creating a new save.\n";
  191. }
  192. if (argc > 3) {
  193. FPS = std::stoi(argv[3]);
  194. }
  195. std::default_random_engine rng(std::chrono::system_clock::now().time_since_epoch().count());
  196. HackIH GD;
  197. GD.bind("GeometryDash.exe");
  198. //std::list<uint32_t> jumps;
  199. std::list<uint32_t> newJumps;
  200. std::list<uint32_t>::iterator nextJump = bestJumps.begin();
  201. double lastJump = 0;
  202. bool randing = false;
  203. std::list<uint32_t> lastDeathPositions;
  204. float globalOffset = 0.0;
  205. float offsetDelta = 2.0;
  206. float lastY = 0.0;
  207. int attempt = 0;
  208. HWND window = FindWindow(NULL, "Geometry Dash");
  209. if (window == NULL) {
  210. std::cerr << "Could not find Geometry Dash window.\n";
  211. return 3;
  212. }
  213. /* === desync debugging === //
  214. float globalDesync = 0.0;
  215. RegisterHotKey(NULL, 1, MOD_CONTROL, VK_ADD);
  216. RegisterHotKey(NULL, 2, MOD_CONTROL, VK_SUBTRACT);
  217. // ======================== */
  218. RegisterHotKey(NULL, 3, MOD_CONTROL, VK_BACK);
  219. while (true) {
  220. float xPos = GD.Read<float>({ GD.BaseAddress , 0x3222D0 , 0x164, 0x224, 0x67C }) + globalOffset /*+ globalDesync*/; // === desync debugging ===
  221. if (xPos == lastX) continue;
  222. if (bestFitness > 100000) bestFitness = 1; // this may break very long levels
  223. //* === desync debugging === //
  224. MSG message;
  225. if (PeekMessage(&message, NULL, WM_HOTKEY, WM_HOTKEY, PM_REMOVE)) {
  226. //if (message.wParam == 1) {globalDesync += 1.0; std::cout << "simulating desync by +1.0 (now " << globalDesync << ")\n";}
  227. //else if (message.wParam == 2) {globalDesync -= 1.0; std::cout << "simulating desync by -1.0 (now " << globalDesync << ")\n";}
  228. if (message.wParam == 3) {
  229. std::cout << "removing last jump from jump list\n";
  230. bestJumps.pop_back();
  231. if (bestJumps.empty()) bestLastJump = 1;
  232. else bestLastJump = bestJumps.back();
  233. bestFitnessR = bestFitness;
  234. bestFitness = bestLastJump;
  235. failCount = 0;
  236. //globalOffset = 0.0;
  237. offsetDelta = 2.0;
  238. saveLevel(argv);
  239. std::cout << "best fitness is now " << bestFitness << "\n";
  240. }
  241. }
  242. // ======================== */
  243. bool shouldJump = false;
  244. float yPos = GD.Read<float>({ GD.BaseAddress , 0x3222D0 , 0x164, 0x224, 0x680 });
  245. //if (xPos != lastX) {
  246. Mode oldmode = mode;
  247. mode = toMode(GD.Read<uint32_t>({GD.BaseAddress, 0x3222D0, 0x164, 0x224, 0x63C}), GD.Read<uint32_t>({GD.BaseAddress, 0x3222D0, 0x164, 0x224, 0x638}));
  248. if (mode != oldmode && xPos > lastX) {
  249. std::cout << "switched between modes (" << modeNames[(int)oldmode] << " -> " << modeNames[(int)mode] << ")\n";
  250. if (isDown) {
  251. jump(GD, window, false);
  252. isDown = false;
  253. }
  254. }
  255. //}
  256. bool canJump = GD.Read<uint8_t>({GD.BaseAddress, 0x3222D0, 0x164, 0x224, 0x640}) || GD.Read<uint8_t>({GD.BaseAddress, 0x3222D0, 0x164, 0x224, 0x66C, 0x20, 0});
  257. uint32_t percentage_int = GD.Read<uint32_t>({ GD.BaseAddress , 0x3222D0 , 0x164, 0x3C0, 0x12C });
  258. char percentage[4] = {percentage_int & 0xFF, (percentage_int >> 8) & 0xFF, (percentage_int >> 16) & 0xFF, (percentage_int >> 24) & 0xFF};
  259. if (percentage[0] == '1' && percentage[1] == '0' && percentage[2] == '0' && percentage[3] == '%') {
  260. std::cout << "level complete! saving and exiting\n";
  261. for (uint32_t j : newJumps) bestJumps.push_back(j);
  262. bestFitness = lastX;
  263. bestLastJump = lastJump;
  264. saveLevel(argv);
  265. return 0;
  266. }
  267. if (xPos > lastX && abs(lastX - globalOffset) < 0.5) std::cout << "[research] delta at beginning is " << xPos - lastX << ", offset is " << xPos - globalOffset - 5.0 << "\n";
  268. if (isDead) {
  269. std::cout << "dead (" << lastX << ", " << lastY << ") (fitness " << bestFitness << ") (";
  270. randing = false;
  271. lastDeathPositions.push_back((uint32_t)lastX);
  272. if (lastDeathPositions.size() > MAX_ATTEMPTS / 2) lastDeathPositions.pop_front();
  273. if (isDown) {
  274. jump(GD, window, false);
  275. isDown = false;
  276. }
  277. if (lastY >= 2700.0) {
  278. std::cout << (MAX_ATTEMPTS - failCount) << " tries until regression)\nnot saving this one since we fell out of bounds\n";
  279. if (bestJumps.size() > 0 && (signed)*bestJumps.rbegin() - (signed)xPos <= 1000 && ++failCount >= MAX_ATTEMPTS) goto regress;
  280. } else if (lastX > bestFitness && (lastX > bestFitnessR || failCount < 9)) {
  281. std::cout << (MAX_ATTEMPTS - failCount /*- (lastX <= bestFitnessR)*/) << " tries until regression)\n" << "best fitness @ " << lastX << " vs. " << bestFitness << "\n";
  282. bestFitness = lastX;
  283. if (lastX > bestFitnessR) {
  284. for (uint32_t j : newJumps) bestJumps.push_back(j);
  285. bestLastJump = lastJump;
  286. bestFitnessR = 0;
  287. failCount = 0;
  288. //globalOffset = 0.0;
  289. offsetDelta = 2.0;
  290. saveLevel(argv);
  291. } else {
  292. //failCount++;
  293. //if (bestFitness > bestLastJump) bestFitness = bestLastJump;
  294. std::cout << "not saving this one since it can be better\n";
  295. }
  296. } else if (bestJumps.empty()) {
  297. std::cout << (MAX_ATTEMPTS - ++failCount) << " tries until regression)\n";
  298. } else if (bestJumps.size() > 0 && (signed)*bestJumps.rbegin() - (signed)xPos <= 1000 && ++failCount >= MAX_ATTEMPTS) {
  299. regress:
  300. std::cout << (MAX_ATTEMPTS - failCount) << " tries until regression)\n";
  301. /*if (jumps.size() == 0 && bestJumps.size() >= MAX_ATTEMPTS / 2) {
  302. std::cerr << "forgot how to play! stopping to prevent data loss\n";
  303. return 3;
  304. }*/
  305. std::cout << "too many fails, going back\n";
  306. bestJumps.pop_back();
  307. if (bestJumps.empty()) bestLastJump = 1;
  308. else bestLastJump = bestJumps.back();
  309. bestFitnessR = bestFitness;
  310. bestFitness = bestLastJump;
  311. failCount = 0;
  312. //globalOffset = 0.0;
  313. offsetDelta = 2.0;
  314. saveLevel(argv);
  315. } else if (lastDeathPositions.size() >= 5 && (/*bestFitness < 1000.0 ||*/ lastX < bestFitness - 1000.0) && std::all_of(lastDeathPositions.begin(), lastDeathPositions.end(), [lastDeathPositions](uint32_t val) -> bool {return abs((double)val - (double)lastDeathPositions.front()) < 15.0;})) { // the last 5 deaths were within 15 units of each other
  316. std::cout << (MAX_ATTEMPTS - failCount) << " tries until regression)\n" << "we're stuck here! ";
  317. /*std::list<uint32_t> lostJumps;
  318. for (int i = 0; i < 200; i += 5) {
  319. if (bestJumps.find((uint32_t)floor(lastX / 5) * 5 - i) != bestJumps.end() && jumps.find((uint32_t)floor(lastX / 5) * 5 - i) == jumps.end()) {
  320. lostJumps.push_back((uint32_t)floor(lastX / 5) * 5 - i);
  321. }
  322. }
  323. // try to fix any lost jumps
  324. if (!lostJumps.empty()) {
  325. std::cout << "looks like some jumps were lost - fixing\n";
  326. // for now we'll just subtract 5 from each lost jump
  327. // maybe we'll need to check to see if it needs to go up/down?
  328. for (uint32_t jump : lostJumps) {
  329. std::cout << "fixing lost jump at " << jump << "\n";
  330. bestJumps.erase(jump);
  331. bestJumps.insert(jump - 5);
  332. }
  333. // adjust offsets if the coordinates desynced
  334. } else {
  335. / *std::cout << "looks like the coordinates got desynced - fixing\n";
  336. if (globalOffset >= offsetDelta * 8.0) {
  337. if (offsetDelta <= 0.25) {
  338. std::cout << "looks like it's broken for good - trying again, but manual intervention will likely be necessary\n";
  339. globalOffset = 0.0;
  340. offsetDelta = 2.0;
  341. } else {
  342. globalOffset = 0.0;
  343. offsetDelta /= 2.0;
  344. std::cout << "offset went over the offset boundaries, restarting with new delta " << offsetDelta << "\n";
  345. }
  346. } else if (globalOffset > 0.0) globalOffset = -globalOffset;
  347. else globalOffset = -globalOffset + offsetDelta;
  348. std::cout << "global offset is now at " << globalOffset << "\n";
  349. // don't try to adjust for the next 10 attempts
  350. lastDeathPositions.push_back(0);
  351. lastDeathPositions.pop_front();* /
  352. }*/
  353. } else {
  354. std::cout << (MAX_ATTEMPTS - failCount) << " tries until regression)\n";
  355. //bestFitnessR = 0;
  356. }
  357. newJumps.clear();
  358. nextJump = bestJumps.begin();
  359. lastJump = 0;
  360. shouldJump = false;
  361. if (++attempt > 1000) {
  362. std::cout << "re-entering level to avoid breaking\nPlease Wait...\n";
  363. keybd_event(VK_ESCAPE, 0x01, 0, NULL);
  364. Sleep(50);
  365. keybd_event(VK_ESCAPE, 0x01, KEYEVENTF_KEYUP, NULL);
  366. Sleep(100);
  367. keybd_event(VK_ESCAPE, 0x01, 0, NULL);
  368. Sleep(50);
  369. keybd_event(VK_ESCAPE, 0x01, KEYEVENTF_KEYUP, NULL);
  370. Sleep(1500);
  371. keybd_event(VK_SPACE, 0x1c, 0, NULL);
  372. Sleep(50);
  373. keybd_event(VK_SPACE, 0x1c, KEYEVENTF_KEYUP, NULL);
  374. Sleep(1000);
  375. attempt = 0;
  376. globalOffset = 0.0;
  377. offsetDelta = 2.0;
  378. }
  379. while (isDead) mode = toMode(GD.Read<uint32_t>({GD.BaseAddress, 0x3222D0, 0x164, 0x224, 0x63C}), GD.Read<uint32_t>({GD.BaseAddress, 0x3222D0, 0x164, 0x224, 0x638}));
  380. float oldX = xPos;
  381. while (oldX == xPos) xPos = GD.Read<float>({ GD.BaseAddress , 0x3222D0 , 0x164, 0x224, 0x67C }) + globalOffset;
  382. lastX = xPos;
  383. continue;
  384. } else if (nextJump != bestJumps.end()) {
  385. if (xPos >= *nextJump) {
  386. shouldJump = true;
  387. nextJump++;
  388. }
  389. } else if (xPos > lastX) {
  390. if (!randing) {
  391. std::cout << "randing after " << bestLastJump << ", odds are " << (ODDS) * 100 << "%\n";
  392. randing = true;
  393. }
  394. double rnum = ((double)rng() / (double)rng.max());
  395. if (rnum < ODDS && (canJump || isDown)) shouldJump = true;
  396. }
  397. if (shouldJump) {
  398. if (randing) {
  399. newJumps.push_back(xPos);
  400. std::cout << "clicking!";
  401. } else std::cout << "clicking";
  402. std::cout << (modeFlying[(int)mode] || isDown ? (isDown ? " off " : " on ") : " ") << "(" << xPos << ")\n";
  403. lastJump = xPos;
  404. if (modeFlying[(int)mode] || isDown) {
  405. isDown = !isDown;
  406. jump(GD, window, isDown);
  407. } else {
  408. jump(GD, window, true);
  409. if (GD.Read<uint8_t>({GD.BaseAddress, 0x3222D0, 0x164, 0x224, 0x641})) isDown = true; // handle hold ring
  410. else jump(GD, window, false);
  411. }
  412. }
  413. if (xPos > lastX) lastY = yPos;
  414. lastX = xPos;
  415. }
  416. }
  417.  
Add Comment
Please, Sign In to add comment