Advertisement
Guest User

Noita alchemy thing

a guest
Nov 13th, 2019
274
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.64 KB | None | 0 0
  1. # horrible python garbage written by Jaitsu
  2. # concept and original C++ implementation credit goes to drgg/Darg
  3. # i'm sorry mine doesn't have hotkeys, tkinter is pain and so is pynput
  4.  
  5. from ctypes import *
  6. from ctypes.wintypes import *
  7. from os import system, path
  8. import sys
  9. import psutil
  10. import requests
  11.  
  12. SEEDADDRFILE = "noita_seed_address.txt"
  13.  
  14. # at time of writing this is the seed address for the october 16th beta
  15. ADDRESS_MIN = 0x01400000
  16. ADDRESS_MAX = 0x014DD1E3
  17. DEFAULTADDR = 0x014DC9E0
  18.  
  19. # you need to be admin or have UAC off in order to run this, so let's kill two birds with one stone
  20. def is_admin():
  21. try:
  22. return windll.shell32.IsUserAnAdmin()
  23. except:
  24. return False
  25.  
  26. if not is_admin():
  27. print("Not running as admin. Attempting elevation...")
  28. try:
  29. windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
  30. except:
  31. print()
  32. print("Can't get admin access. We need that to read Noita's memory for the seed.")
  33. finally:
  34. sys.exit()
  35.  
  36. # shamelessly ganked from drgg
  37. matDict = {
  38. "water": "Water (mat_water)",
  39. "water_ice": "Chilly Water (mat_water_ice)",
  40. "water_swamp": "Swamp (mat_water_swamp)",
  41. "oil": "Oil (mat_oil)",
  42. "alcohol": "Whiskey (mat_alcohol)",
  43. "swamp": "Swamp (mat_swamp)",
  44. "mud": "Mud (mat_mud)",
  45. "blood": "Blood (mat_blood)",
  46. "blood_fungi": "Fungus (mat_blood_fungi)",
  47. "blood_worm": "Worm Blood (mat_blood_worm)",
  48. "radioactive_liquid": "Toxic Sludge (mat_radioactive_liquid)",
  49. "cement": "Cement (mat_cement)",
  50. "acid": "Acid (mat_acid)",
  51. "lava": "Lava (mat_lava)",
  52. "urine": "Urine (mat_urine)",
  53. "poison": "Glowing Liquid (mat_poison)",
  54. "magic_liquid_teleportation": "Teleportatium (mat_magic_liquid_teleportation)",
  55. "magic_liquid_polymorph": "Polymorphine (mat_magic_liquid_polymorph)",
  56. "magic_liquid_random_polymorph": "Chaotic Polymorphine (mat_magic_liquid_random_polymorph)",
  57. "magic_liquid_berserk": "Berserkium (mat_magic_liquid_berserk)",
  58. "magic_liquid_charm": "Pheromone (mat_magic_liquid_charm)",
  59. "magic_liquid_invisibility": "Invisiblium (mat_magic_liquid_invisibility)",
  60. "sand": "Sand (mat_sand)",
  61. "bone": "Bone (mat_bone)",
  62. "soil": "Soil (mat_soil)",
  63. "honey": "Honey (mat_honey)",
  64. "slime": "Slime (mat_slime_pink)",
  65. "snow": "Snow (mat_snow)",
  66. "rotten_meat": "Rotten Meat (mat_rotten_meat)",
  67. "wax": "Wax (mat_wax)",
  68. "gold": "Gold (mat_gold)",
  69. "silver": "Silver (mat_silver) (UNOBTAINABLE)",
  70. "copper": "Copper (mat_copper)",
  71. "brass": "Brass (mat_brass)",
  72. "diamond": "Diamond (mat_diamond)",
  73. "coal": "Coal (mat_coal)",
  74. "gunpowder": "Gunpowder (mat_gunpowder)",
  75. "gunpowder_explosive": "Gunpowder (mat_gunpowder_explosive)",
  76. "grass": "Grass (mat_grass)",
  77. "fungi": "Fungus (mat_fungus)"
  78. }
  79.  
  80. def findSeedAddress(seedtofind):
  81. # get Noita's process ID
  82. noitaProcId = 0;
  83.  
  84. for proc in psutil.process_iter():
  85. pinfo = proc.as_dict(attrs=['pid', 'name'])
  86. if "noita" in pinfo['name'].lower():
  87. noitaProcId = int(pinfo['pid'])
  88.  
  89. if noitaProcId == 0:
  90. return(-1)
  91. # okay to preface this I barely have a clue what I'm doing and this might not work properly
  92. # if the value of the seed you're searching by happens to appear literally anywhere else between
  93. # ADDRESS_MIN and ADDRESS_MAX but oh well, if it gets the wrong address just restart and try again
  94. # as long as you're on the same build the address doesn't change
  95. #
  96. # in my experience, sometimes the first address is a false positive but it appears twice so taking
  97. # the second result is your best shot
  98.  
  99. PROCESS_ALL_ACCESS = 0x1F0FFF
  100. buffer = c_char_p(b'0000')
  101. val = c_int()
  102. bufferSize = 4
  103. bytesRead = c_ulong(0)
  104. addresses = []
  105.  
  106. processHandle = windll.kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, noitaProcId)
  107.  
  108. for address in range(ADDRESS_MIN, ADDRESS_MAX):
  109. if windll.kernel32.ReadProcessMemory(processHandle, address, buffer, bufferSize, byref(bytesRead)):
  110. memmove(ctypes.byref(val), buffer, ctypes.sizeof(val))
  111. if val.value == seedtofind:
  112. addresses.append(address)
  113. else:
  114. windll.kernel32.CloseHandle(processHandle)
  115. return(-2)
  116. if(len(addresses) > 1):
  117. break
  118.  
  119. windll.kernel32.CloseHandle(processHandle)
  120. if(len(addresses) <= 1):
  121. return(-3)
  122. else:
  123. return(addresses[1])
  124.  
  125. def getSeed(address):
  126. # get Noita's process ID
  127. noitaProcId = 0;
  128.  
  129. for proc in psutil.process_iter():
  130. pinfo = proc.as_dict(attrs=['pid', 'name'])
  131. if "noita" in pinfo['name'].lower():
  132. noitaProcId = int(pinfo['pid'])
  133.  
  134. # read the seed from Noita's memory - TODO: find way to dynamically find seed address
  135. # look I barely comprehend all this I just ganked it from stackoverflow and repurposed it
  136.  
  137. PROCESS_ALL_ACCESS = 0x1F0FFF
  138.  
  139. buffer = c_char_p(b'0000')
  140. val = c_int()
  141. bufferSize = 4
  142. bytesRead = c_ulong(0)
  143.  
  144. processHandle = windll.kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, noitaProcId)
  145.  
  146. if windll.kernel32.ReadProcessMemory(processHandle, address, buffer, bufferSize, byref(bytesRead)):
  147. windll.kernel32.CloseHandle(processHandle)
  148. memmove(ctypes.byref(val), buffer, ctypes.sizeof(val))
  149. return(val.value)
  150. else:
  151. windll.kernel32.CloseHandle(processHandle)
  152. return(-1)
  153.  
  154. def doSeedCheck(seed):
  155. if(int(seed) <= 0):
  156. return("Error: Failed to get seed.")
  157. resultUrl = "http://94.172.33.134:4921/noita?" + str(seed) + "&hey_you_reading_this_you_will_find_literally_nothing_and_just_waste_your_time"
  158. response = requests.get(resultUrl)
  159.  
  160. if response.status_code != 200:
  161. return("Error: Server returned status code "+str(response.status_code)+".")
  162.  
  163. responseText = response.text
  164. responseTextStripped = responseText.replace(';',',')
  165. responseTextSplit = responseTextStripped.split(',')
  166.  
  167. msgboxstring = "Seed: "+str(seed)+"\n"\
  168. +"(If this is wrong, please search for or enter the correct seed address.)"\
  169. +"\n"\
  170. +"\n"\
  171. +"Lively Concoction ("+responseTextSplit[1]+"%):"+"\n"\
  172. +"\n"\
  173. +matDict[responseTextSplit[2]]+"\n"\
  174. +matDict[responseTextSplit[3]]+"\n"\
  175. +matDict[responseTextSplit[4]]+"\n"\
  176. +"\n"\
  177. +"\n"\
  178. +"Alchemical Precursor ("+responseTextSplit[6]+"%):"+"\n"\
  179. +"\n"\
  180. +matDict[responseTextSplit[7]]+"\n"\
  181. +matDict[responseTextSplit[8]]+"\n"\
  182. +matDict[responseTextSplit[9]]
  183.  
  184. return(msgboxstring)
  185.  
  186. def theWholeShebang(seedaddress):
  187. seed = getSeed(seedaddress)
  188. message = doSeedCheck(seed)
  189. system("cls")
  190. print(message)
  191.  
  192. def updateSavedSeedAddr(newseed):
  193. seedfile = open(SEEDADDRFILE, "w")
  194. seedfile.write(hex(newseed))
  195. seedfile.close()
  196. print("Updated saved seed address: "+hex(newseed))
  197.  
  198. ####################################################
  199.  
  200. system("cls")
  201. seedaddress = DEFAULTADDR
  202.  
  203. if path.exists(SEEDADDRFILE):
  204. newseed = 0
  205. addrfile = open(SEEDADDRFILE, "r")
  206. try:
  207. newseedaddr = int(addrfile.readline(), 16)
  208. seedaddress = newseedaddr
  209. print("Read seed address from file: "+hex(newseedaddr))
  210. except:
  211. print("Error reading seed address file!")
  212. print("Using default seed address ("+hex(seedaddress)+").")
  213. finally:
  214. addrfile.close()
  215. print()
  216. print()
  217.  
  218. while True:
  219. print("CURRENT SEED ADDRESS: "+hex(seedaddress))
  220. print()
  221. print()
  222. selection = 0
  223. presel = input("""Choose from the following:
  224.  
  225. 1: Check info for seed (using current address)
  226. 2: Search for new seed address
  227. 3: Manually look up a seed
  228. 4: Enter a new seed address manually
  229. 5: Exit
  230.  
  231. Selection: """)
  232. try:
  233. selection = int(presel)
  234. except:
  235. pass
  236.  
  237. if selection == 1 or presel == "":
  238. theWholeShebang(seedaddress)
  239. elif selection < 1 or selection > 5:
  240. print("Invalid selection.")
  241. elif selection == 1 or presel == "":
  242. theWholeShebang(seedaddress)
  243. elif selection == 2:
  244. searchseed = int(input("Enter your current seed: "))
  245. newseedaddr = findSeedAddress(searchseed)
  246. if newseedaddr == -1:
  247. print("Couldn't find Noita. Is it running?")
  248. elif newseedaddr == -2:
  249. print("An error occurred trying to access Noita's memory.")
  250. elif newseedaddr == -3:
  251. print("Could not find the address from that seed.")
  252. else:
  253. seedaddress = newseedaddr
  254. print("Found new seed address at "+hex(seedaddress)+".")
  255. updateSavedSeedAddr(newseedaddr)
  256. elif selection == 3:
  257. manualseed = input("Enter the seed you want to search for: ")
  258. system("cls")
  259. print(doSeedCheck(manualseed))
  260. elif selection == 4:
  261. manualaddr = int(input("Enter the new address you want to use. (No 0x, just the hex address.): "), base=16)
  262. if manualaddr < ADDRESS_MIN or manualaddr > ADDRESS_MAX:
  263. print("Invalid address!")
  264. print()
  265. print("(Probably. If you're sure you have the right address,")
  266. print("edit the Python file and change ADDRESS_MIN/ADDRESS_MAX.)")
  267. else:
  268. seedaddress = manualaddr
  269. updateSavedSeedAddr(manualaddr)
  270. elif selection == 5:
  271. print("Goodbye.")
  272. sys.exit()
  273. print()
  274. input("Press Enter to continue.")
  275. system("cls")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement