Last active
August 29, 2015 14:22
-
-
Save imayhaveborkedit/d50eb0e1bdc47039d7db to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys, ctypes | |
sys.dont_write_bytecode = 1 | |
TH32CS_SNAPMODULE = 8 | |
PROCESS_ALL_ACCESS = 0x1F0FFF | |
class MODULEENTRY32(ctypes.Structure): | |
_fields_ = [ ( 'dwSize' , ctypes.c_long ) , | |
( 'th32ModuleID' , ctypes.c_long ), | |
( 'th32ProcessID' , ctypes.c_long ), | |
( 'GlblcntUsage' , ctypes.c_long ), | |
( 'ProccntUsage' , ctypes.c_long ) , | |
( 'modBaseAddr' , ctypes.c_long ) , | |
( 'modBaseSize' , ctypes.c_long ) , | |
( 'hModule' , ctypes.c_void_p ) , | |
( 'szModule' , ctypes.c_char * 256 ), | |
( 'szExePath' , ctypes.c_char * 260 ) ] | |
def read_memory_address(pid, address, offset): | |
buf = ctypes.c_char_p(b"Datas") | |
bufferSize = len(buf.value) | |
bytesRead = ctypes.c_ulong(1) | |
processHandle = ctypes.windll.kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, pid) | |
if ctypes.wintypes.windll.kernel32.ReadProcessMemory(processHandle, address + offset, buf, bufferSize, ctypes.byref(bytesRead)): | |
ctypes.windll.kernel32.CloseHandle(processHandle) | |
# print 'mem read error: %d' % ctypes.windll.kernel32.GetLastError() | |
return ctypes.cast(buf, ctypes.POINTER(ctypes.c_ubyte)).contents.value | |
else: | |
ctypes.windll.kernel32.CloseHandle(processHandle) | |
raise RuntimeError("Could not read address") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import win32api | |
import win32gui | |
import win32process | |
import ctypes | |
import ctypes.wintypes | |
import sys, os, time, struct, textwrap | |
import memread | |
from contextlib import contextmanager | |
from Queue import Queue | |
sys.dont_write_bytecode = 1 | |
################################################################################ | |
SPINNER= ['|', '/', '-', '\\'] | |
STATMAP = { | |
'Intelligence': 0xA963ED2, | |
'Will': 0xA963ECF, | |
'Strength': 0xA963EC2, | |
'Endurance': 0xA963EC9, | |
'Dexterity': 0xA963EC6, | |
'Agility': 0xA963EC3, | |
'Speed': 0xA963EC7, | |
'Eyesight': 0xA963ECD, | |
'Hearing': 0xA963ED3, | |
'Smell/Taste': 0xA963ECA, | |
'Touch': 0xA963ECE, | |
'Height': 0xA963EB4, | |
'Weight': 0xA963EB0, | |
'Physique': 0xA963EB8 | |
} | |
TH32CS_SNAPMODULE = 8 | |
class MODULEENTRY32(ctypes.Structure): | |
_fields_ = [ ( 'dwSize' , ctypes.c_long ) , | |
( 'th32ModuleID' , ctypes.c_long ), | |
( 'th32ProcessID' , ctypes.c_long ), | |
( 'GlblcntUsage' , ctypes.c_long ), | |
( 'ProccntUsage' , ctypes.c_long ) , | |
( 'modBaseAddr' , ctypes.c_long ) , | |
( 'modBaseSize' , ctypes.c_long ) , | |
( 'hModule' , ctypes.c_void_p ) , | |
( 'szModule' , ctypes.c_char * 256 ), | |
( 'szExePath' , ctypes.c_char * 260 ) ] | |
class TextReader(object): | |
def __init__(self, tessdir): | |
self.api = tesseract.TessBaseAPI() | |
self.api = tesseract.TessBaseAPI() | |
self.api.SetOutputName("outputName"); | |
self.api.Init(tessdir, "eng", tesseract.OEM_DEFAULT) | |
self.api.SetPageSegMode(tesseract.PSM_AUTO) | |
def __del__(self): | |
self.api.End() | |
def get_image_text(self, imagename): | |
self.api.SetImage(tesseract.pixRead(imagename)) | |
return self.api.GetUTF8Text() | |
@contextmanager | |
def wait_for_True(execfunc, args=None, index=None, waittime=1, spin=False, spinnertext=''): | |
spinpos = 0 | |
while True: | |
try: | |
if args: | |
data = execfunc(*args) | |
else: | |
data = execfunc() | |
except: | |
data = 0 if not index else [0]*(index+1) | |
# print data | |
if index: | |
if data[index]: | |
if spin: print | |
yield data[index] | |
break | |
else: | |
if spin: | |
print spinnertext + SPINNER[spinpos] + '\r', | |
spinpos += 1 | |
if spinpos > 3: | |
spinpos = 0 | |
time.sleep(waittime) | |
else: | |
if data: | |
if spin: print | |
yield data | |
break | |
else: | |
if spin: | |
print spinnertext + SPINNER[spinpos] + '\r', | |
spinpos += 1 | |
if spinpos > 3: | |
spinpos = 0 | |
time.sleep(waittime) | |
########################################################################################## | |
def _is_game_running(): | |
toplist, winlist = [], [] | |
def enum_cb(hwnd, results): | |
winlist.append((hwnd, win32gui.GetWindowText(hwnd))) | |
win32gui.EnumWindows(enum_cb, toplist) | |
urw = [(hwnd, title) for hwnd, title in winlist if 'UnReal World' in title] | |
if urw: return len(urw), urw[0][0] | |
else: return (False, None) | |
def _get_game_base_addr(): | |
hModuleSnap = ctypes.c_void_p(0) | |
me32 = MODULEENTRY32() | |
me32.dwSize = ctypes.sizeof(MODULEENTRY32) | |
hModuleSnap = ctypes.windll.kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, get_game_pid()) | |
ret = ctypes.windll.kernel32.Module32First(hModuleSnap, ctypes.pointer(me32)) | |
ctypes.windll.kernel32.CloseHandle(hModuleSnap) | |
if ret == 0 : | |
print 'ListProcessModules() Error on Module32First[%d]' % ctypes.windll.kernel32.GetLastError() | |
return False | |
return me32.modBaseAddr | |
def getTerminalSize(): | |
res = None | |
try: | |
h = ctypes.windll.kernel32.GetStdHandle(-12) | |
csbi = ctypes.create_string_buffer(22) | |
res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi) | |
except: | |
return [None, None] | |
if res: | |
(bufx, bufy, curx, cury, wattr, | |
left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw) | |
sizex = right - left + 1 | |
sizey = bottom - top + 1 | |
return sizex, sizey | |
else: | |
return [None, None] | |
def get_game_running(): | |
return _is_game_running()[0] | |
def get_game_hwnd(): | |
return _is_game_running()[1] | |
def get_game_pid(): | |
return win32process.GetWindowThreadProcessId(get_game_hwnd())[1] | |
def get_game_baseaddr(): | |
return _get_game_base_addr() | |
def game_is_active_window(): | |
return win32gui.GetForegroundWindow() == get_game_hwnd() | |
def read_stat(stat): | |
reload(memread) | |
if stat == 'Weight': | |
byte1 = memread.read_memory_address(get_game_pid(), STATMAP[stat], get_game_baseaddr()) | |
byte2 = memread.read_memory_address(get_game_pid(), STATMAP[stat] + 1, get_game_baseaddr()) | |
return byte1 + (byte2 << 8) | |
else: | |
s = memread.read_memory_address(get_game_pid(), STATMAP[stat], get_game_baseaddr()) | |
return s | |
def read_all_stats(): | |
return {st:read_stat(st) for st in STATMAP.keys()} | |
def inches_to_feet(inches): | |
return '%s\'%s"' % (int(inches)/12, int(inches) % 12) | |
def create_text_stat_bar(num, physique=False): | |
if physique: | |
return '[ %s ]' % ' '.join(list('----@----')[num-1:num+4][::-1]) | |
return '[%s%s]' % ('='*num, ' ' * (18-num)) | |
def wrap_text(te): | |
return '\n'.join(textwrap.wrap(te, width=getTerminalSize()[0]-1)) | |
def format_stats(curstats): | |
return '\n'.join([ | |
'{:13} {:2} {:<}'.format( 'Intelligence:', curstats['Intelligence'], create_text_stat_bar(curstats['Intelligence'])), | |
'{:13} {:2} {:<}'.format( 'Will:', curstats['Will'], create_text_stat_bar(curstats['Will'])), | |
'', | |
'{:13} {:2} {:<}'.format( 'Strength:', curstats['Strength'], create_text_stat_bar(curstats['Strength'])), | |
'{:13} {:2} {:<}'.format( 'Endurance:', curstats['Endurance'], create_text_stat_bar(curstats['Endurance'])), | |
'{:13} {:2} {:<}'.format( 'Dexterity:', curstats['Dexterity'], create_text_stat_bar(curstats['Dexterity'])), | |
'{:13} {:2} {:<}'.format( 'Agility:', curstats['Agility'], create_text_stat_bar(curstats['Agility'])), | |
'{:13} {:2} {:<}'.format( 'Speed:', curstats['Speed'], create_text_stat_bar(curstats['Speed'])), | |
'{:13} {:2} {:<}'.format( 'Eyesight:', curstats['Eyesight'], create_text_stat_bar(curstats['Eyesight'])), | |
'{:13} {:2} {:<}'.format( 'Hearing:', curstats['Hearing'], create_text_stat_bar(curstats['Hearing'])), | |
'{:13} {:2} {:<}'.format( 'Smell/Taste:', curstats['Smell/Taste'], create_text_stat_bar(curstats['Smell/Taste'])), | |
'{:13} {:2} {:<}'.format( 'Touch:', curstats['Touch'], create_text_stat_bar(curstats['Touch'])), | |
'', | |
'{:13} {}" ({})'.format( 'Height:', curstats['Height'], inches_to_feet(curstats['Height'])), | |
'{:13} {} lbs'.format( 'Weight:', curstats['Weight']), | |
'', | |
'{:13} Type {} {}'.format( 'Physique:', curstats['Physique'], create_text_stat_bar(curstats['Physique'], True)) ]) | |
def press_n(): | |
win32api.keybd_event(78, 0, 1, 0) | |
time.sleep(0.01) | |
win32api.keybd_event(78, 0, 2, 0) | |
def input_stat_constraints(): | |
target_stats = {} | |
statlist = ['Intelligence','Will','Strength','Endurance','Dexterity','Agility', | |
'Speed','Eyesight','Hearing','Smell/Taste','Touch','Height','Weight','Physique'] | |
def _check_input(tinput, stat): | |
tinput = tinput.replace(' ', '') | |
isint = isrange = isletter = isnone = False | |
isnone = tinput == '' | |
try: | |
if int(tinput): | |
if stat in ['Height','Weight'] and 1 <= int(tinput) <= 300: | |
isint = True; raise Exception() | |
elif stat in ['Intelligence','Will','Strength','Endurance','Dexterity', | |
'Agility','Speed','Eyesight','Hearing','Smell/Taste','Touch'] and 1 <= int(tinput) <= 18: | |
isint = True; raise Exception() | |
elif stat == 'Physique' and 1 <= int(tinput) <= 5: | |
isint = True; raise Exception() | |
else: | |
return False | |
except: pass | |
else: isint = True | |
try: | |
if '-' in tinput and not tinput.startswith('-'): | |
tval1, tval2 = tinput.split('-') | |
int(tval1); int(tval2) | |
if tval1 > tval2: return False | |
isrange = True | |
except: return False | |
# isletter = True if tinput.lower() in ['b', 'r'] else False | |
return (isint or isrange or isletter or isnone) | |
def _parse_input(target_val, stat): | |
target_val = target_val.replace(' ', '') | |
if target_val == '': | |
target_stats[stat+'_min'] = 0 | |
target_stats[stat+'_max'] = 2**9 | |
return | |
#if target_val.lower() == 'r': | |
# ask_for_stat(statlist[0]) | |
# return | |
#if target_val.lower() == 'b': | |
# gotostat = statlist.index(stat) - 1 | |
# if gotostat < 0: | |
# print 'There\'s nowhere to go but forwards.' | |
# ask_for_stat(statlist[0]) | |
# return | |
# else: | |
# ask_for_stat(statlist[gotostat]) | |
# return | |
if '-' in target_val: | |
tmin, tmax = target_val.split('-') | |
target_stats[stat+'_min'] = int(tmin) | |
target_stats[stat+'_max'] = int(tmax) | |
return | |
if int(target_val): | |
target_stats[stat+'_min'] = int(target_val) | |
target_stats[stat+'_max'] = 2**9 | |
return | |
print "Values were not recorded? Something bad has happened." | |
def ask_for_stat(stat): | |
while True: | |
target_val = raw_input('%s: ' % stat) | |
if _check_input(target_val, stat): | |
_parse_input(target_val, stat) | |
break | |
else: | |
print 'Invalid input:', target_val, '\n' | |
print wrap_text('Enter a minimum target value for each stat. Stats are 1 to 18, height goes up to somewhere below 300, physique is 1 to 5, height is in inches, weight is in pounds.') | |
print 'Input format:' | |
print ' x - Single target minimum value. Ex: 16' | |
print ' x-y - Target range. Ex: 15-18' | |
print ' - Empty line (just press enter) for no bounds' | |
# print ' b - Go back one stat.' | |
# print ' r - Start again from the beginning.' | |
for stat in statlist: | |
if stat in ['Strength', 'Height']: print | |
ask_for_stat(stat) | |
return target_stats | |
def compare_stats_with_constraints(stats, constraints): | |
for stat in stats: | |
if not (constraints[stat+'_min'] <= stats[stat] <= constraints[stat+'_max']): | |
return False | |
return True | |
def main(): | |
print 'UnReal World Stat Roller is starting...' | |
if not get_game_running(): | |
print 'UnReal World is not running, please start the game.\n' | |
with wait_for_True(get_game_running, spin=True, spinnertext='Waiting for game ') as res: | |
print 'UnReal World process found.' | |
else: | |
print 'UnReal World is running.' | |
print 'UnReal World PID is', get_game_pid() | |
print 'UnReal World base address is', hex(get_game_baseaddr()) | |
constraints = input_stat_constraints() # MAYBE PICKLE STATS AND LOAD THEM FOR NEXT RUN | |
raw_input(wrap_text('All stats entered. Press Enter to begin rolling. Make sure you\'re on the stats screen!')) | |
def statloopprint(s, b): | |
if b: | |
print s | |
rollcount = 0 | |
laststats = None | |
while True: | |
curstats = read_all_stats() | |
diffstats = laststats != curstats | |
if True: | |
if diffstats: | |
os.system('cls') | |
statloopprint(format_stats(curstats)+'\n', diffstats) | |
statloopprint('Total rerolls: %s\n' % rollcount, diffstats) | |
statsgood = compare_stats_with_constraints(curstats, constraints) | |
if statsgood: | |
statloopprint(wrap_text('Are these stats acceptable? If not, reroll them in the game. If they are, close this program or press Control + c'), diffstats) | |
time.sleep(0.1) | |
laststats = curstats | |
continue | |
if game_is_active_window(): | |
press_n() | |
rollcount += 1 | |
else: | |
statloopprint('\n[Rolling paused: Game not in focus]', diffstats) | |
time.sleep(0.2) | |
laststats = curstats | |
if __name__ == '__main__': | |
try: | |
main() | |
except KeyboardInterrupt as e: | |
print "\nExiting." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment