Skip to content

Instantly share code, notes, and snippets.

@imayhaveborkedit
Last active August 29, 2015 14:22
Show Gist options
  • Save imayhaveborkedit/d50eb0e1bdc47039d7db to your computer and use it in GitHub Desktop.
Save imayhaveborkedit/d50eb0e1bdc47039d7db to your computer and use it in GitHub Desktop.
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")
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
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.'
print
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())
print
constraints = input_stat_constraints() # MAYBE PICKLE STATS AND LOAD THEM FOR NEXT RUN
print
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