# QA Functions Test # Started 28/08/08 # TKP import os import sys import shutil import time import subprocess import filecmp import msvcrt import random import copy import webbrowser import traceback import string import hashlib #import WConio import re import codecs import socket #====Settings Stuff============================================================= class GID: """ Container for holding all the settings associated with a GID """ def __init__(self,gid, __unicode__ = False): self.settings = {} self.gid = gid self.lists = [] self.__unicode__ = __unicode__ def __getitem__(self,name): return self.GetSetting(name) def __delitem__(self, name): del self.settings[name] def __setitem__(self,name,data): self.AddSetting(name, data) def __iter__(self): return self.SettingsGenerator() def __contains__(self,item): return item in self.settings def __len__(self): return len(self.settings) def SettingsGenerator(self): """ Generator object for use by __iter__ """ for name in self.ListSettings(): yield name def ListSettings(self): """ Return a list of all the setting names present in this GID """ setting_names = [] for key, setting in self.settings.iteritems(): setting_names.append(key) setting_names.sort() return setting_names def AddSetting(self,name,data): """ Add a setting to the settings dictionary """ if type(data) == str and self.__unicode__: data = unicode(data) self.settings[name.lower()] = data def AddList(self,name): """ Mark a setting as a 'list' setting (comma seperated). Used by GetSetting to determine how to return a requested setting """ if name not in self.lists: self.lists.append(name) def CSVToList(self,settings): """ Convert a string into a list of objects, seperated by a comma """ untidy_list = settings.split(',') #remove whitespace tidy_list = [] for item in untidy_list: stripped = item.strip() if stripped == '': continue else: tidy_list.append(stripped) return tidy_list def GetSetting(self,name): """ Return the value of the requested setting. Exit if setting not found """ if not self.SettingExists(name): error_exit('Setting not found\nGAME_ID: %s\nSETTING: %s' % (self.gid,name)) if name in self.lists: return self.CSVToList(self.settings[name]) else: return self.settings[name] def GetRawSetting(self,name): """ Return a setting without processing it. Used to retrieve flat string versions of 'list' settings """ if not self.SettingExists(name): error_exit('Setting not found\nGAME_ID: %s\nSETTING: %s' % (self.gid,name)) return self.settings[name] def SettingExists(self,name): """ Determines whether the setting name exists in this GID """ if name in self.ListSettings(): return True else: return False def Platform(self): """ Returns the platform associated with this GID """ if self.SettingExists('xex'): return 'xbx' elif self.SettingExists('self'): return 'ps3' class SettingsLoader: def __init__(self, __unicode__=False): self.game_ids = {} self.debug = True self.categories = {} self.__unicode__ = __unicode__ def __call__(self,gid,name): return self.GetSetting(gid,name) def __getitem__(self, gid): return self.GetGIDObject(gid) def __delitem__(self, gid): del self.game_ids[gid] def __setitem__(self, gid, data): self.game_ids[gid] = data #this is inefficient and bad #self.GatherCategories() #just remember to refresh categories after an insert def __iter__(self): return self.GIDGenerator() def __len__(self): return len(self.game_ids) def __contains__(self,item): return item in self.game_ids def GIDGenerator(self): for gid in self.ListGIDs(): yield self.GetGIDObject(gid) def GetGIDObject(self,gid): """ Returns a GID object if the object can be found, exits otherwise """ self.CheckForGID(gid) return self.game_ids[gid] def ListGIDs(self): """ Lists all GIDs currently contained in the loader object """ gids = [] for gid,data in self.game_ids.iteritems(): gids.append(gid) gids.sort() return gids def ListSettings(self,gid): """ Returns a list of the names of all the settings currently in a GID """ self.CheckForGID(gid) return self.game_ids[gid].ListSettings() def IsValidGID(self,gid): """ Returns True if a GID is found, False if not """ if gid in self.ListGIDs(): return True else: return False def CheckForGID(self,gid): """ Checks for a game_id, exits if it doesn't exist """ if not self.IsValidGID(gid): error_exit('GID not found: %s' % gid) def SettingExists(self,gid,name): """ Check for presence of gid, then check for presence of setting name in gid """ if not self.IsValidGID(gid): return False return self.game_ids[gid].SettingExists(name) def GetSetting(self,gid,name): """ Check to see if the GID exists, then call the GIDs setting return function """ self.CheckForGID(gid) return self.game_ids[gid].GetSetting(name) def LoadFile(self,filename): """ Populate the list of GIDs with values found in the filename provided """ if not os.path.exists(filename): error_exit('Failed to load settings from "%s". File could not ' 'be found.' % filename) if not os.access(filename,os.R_OK): error_exit('Failed to load settings from "%s". File could not ' 'be read.' % filename) GIDcount = 0 settingscount = 0 try: if self.__unicode__: set_file = codecs.open(filename, 'r', 'utf-8') gid_start = u'[' gid_end = u']' else: set_file = open(filename,'r') gid_start = '[' gid_end = ']' except IOError: error_exit('Failed to load settings from "%s". File could not ' 'be read.' % filename) current_gid = None for line in set_file: #skip the line if it starts with a comment if line.startswith('#'): continue #strip newlines and comments line = line.strip('\n') if '#' in line: line = line[:line.find('#')] #convert to hash while '' in line: line = line[:line.find('')] + '#' + line[line.find('')+6:] line = line.strip() #print line #is this a new GID? #if len(line) > 2: print line[0], line[-1] if line.startswith(gid_start) and line.endswith(gid_end): GIDcount += 1 #print 'gid found: %s' % line current_gid = line.strip('[]').lower() #print 'current_gid: %s' % current_gid if current_gid not in self.ListGIDs(): self.game_ids[current_gid] = GID(current_gid, self.__unicode__) #print 'gid created: %s' % self.game_ids[current_gid].gid continue #ditch the current line if we don't have a GID yet if current_gid is None: #if self.debug: print 'no gids yet' continue #ditch the current line if it doesn't have '=' in it if '=' not in line: continue #build normal entry line_part = line.partition('=') name = line_part[0].strip() data = line_part[2].strip() if name.startswith('LIST:'): name = name[5:].strip() self.game_ids[current_gid].AddList(name) #write entry self.game_ids[current_gid].AddSetting(name,data) settingscount += 1 set_file.close() logging('%s settings in %s gameids loaded from %s' % (str(settingscount),str(GIDcount),filename)) self.GatherCategories() def GatherCategories(self): self.categories = {} for key, gid in self.game_ids.iteritems(): if 'category' in gid: if gid['category'] not in self.categories: self.categories[gid['category']] = [gid] else: self.categories[gid['category']].append(gid) ## print '======SettingsLoader======' ## for key, item in self.categories.iteritems(): ## print key ## print '==========================' def GetCategoryItems(self, category): if category not in self.categories: error_exit('GetCategoryItems: Category not found in SettingsLoader ' 'instance') return self.categories[category] def IsHidden(self, gid): """ DON'T FORGET: Pass me a GID object, not a GID string returns true if a gid is 'hidden', false otherwise """ error_exit('IsHidden broken, do not use') if 'hidden' not in gid: return False else: if gid['hidden'] == '1': return True else: return False def RemoveHiddenGIDs(self): """ delete any GID with a 'hidden' setting with a value of '1' """ for gid in self.ListGIDs(): if not self.game_ids[gid].SettingExists('hidden'): continue if self.game_ids[gid].GetSetting('hidden') == '1': del self.game_ids[gid] logging('Hiding %s' % gid) def DoStringReplacement(self, variables): """ Do string replacement on all settings in all GIDs in loader """ for gid in self.ListGIDs(): for name in self.game_ids[gid].ListSettings(): if '$$' in self.game_ids[gid].GetRawSetting(name): setting_value = self.game_ids[gid].GetRawSetting(name) replacement_setting = ReplaceStringVariables(setting_value, variables) self.game_ids[gid].AddSetting(name,replacement_setting) def ReplaceStringVariables(line,variables): """ Takes a GID container full of variables """ max_levels = 100 #used to prevent infinite replacement loops while line.find('$$') is not -1: if line.find('$$') is line.rfind('$$'): return line v_start = line.find('$$') + 2 v_end = line[v_start:].find('$$') + v_start v_name = line[v_start:v_end] v_string = variables[v_name] line = line[:v_start-2]+v_string+line[v_end+2:] max_levels -= 1 if max_levels is 0: error_exit('Potentially infinite loop detected in ReplaceString' 'Variables(). Looping on line: "%s"' % line) return line def get_setting(gid, name, exitstatus='EXIT'): """ old style get_setting, replace this as sooooon as i can """ if gid == 'defaults': return settings.GetSetting('defaults',name) if exitstatus == 'NO_EXIT': if game_versions.SettingExists(gid,name): return game_versions.GetSetting(gid,name) else: return False return game_versions.GetSetting(gid,name) def SettingsFiles(): files_to_load = [] for switch in command_line_switches(): if switch.lower().startswith('-addsettings='): files_to_load.append(switch[13:]) return files_to_load def command_line_switches(): """ gathers the command line switches """ args = [] for switch in sys.argv[1:]: args.append(switch) return args #=============================================================================== #====Menu Stuff================================================================= ##def get_categories(): ## """Gets all unique categories from game_version dict, returns them in ## a sorted list""" ## categories=[] ## #store unique categories in list ## for game_id in game_version: ## if get_setting(game_id,'category') not in categories: ## categories.append(get_setting(game_id,'category')) ## categories.sort() ## return categories ## ## ##def category_menu(): ## """ Creates a menu from all categories found in game_versions.ini """ ## categories = get_categories() ## item_comments = [None]*len(categories) ## item_comments.append('Exit the QA Menu') ## comment = 'Good '+time_of_day()+', '+windows_username()[0]+'. What would you like to play today?' ## ## selection = menu_maker_2('Main Menu', categories,comment,item_comments,back_text='Quit') ## ## if selection == -1: ## selected_category = '_BACK' ## else: ## selected_category = categories[selection] ## ## return selected_category ## ## ##def auto_menu(category): ## """automatically generates a menu from game_version containing all ## items that have the supplied category""" ## menu_id=[] ## clean_name=[] ## item_comments=[] ## for game_id in game_version: ## if get_setting(game_id,'category').lower() == category.lower(): ## menu_id.append(game_id) ## clean_name.append(get_setting(game_id,'name')) ## item_comments.append(get_setting(game_id,'name')) ## ## selection = menu_maker_2(category, clean_name, item_comments=item_comments,NO_SORT=False) ## ## if selection == -1: ## selected_id = '_BACK' ## else: ## selected_id = menu_id[selection] ## ## return selected_id def print_button_menu(menu_title, menu_items, selection, comment=None, NO_BACK=False, left_selector='--> ', right_selector=' <--', back_text='Back', show_numbers=False): """Screen updating function used by menu_maker_2()""" #os.system('cls') spacer = ' '*len(left_selector) ## print '='*len(menu_title) ## print menu_title ## print '='*len(menu_title) os.system('cls') print box_text(menu_title,1) for key,item in enumerate(menu_items): if key==selection: #reverse_colour() if show_numbers: print str(key+1)+'. '+left_selector+item+right_selector else: print left_selector+item+right_selector #text_colour() else: if show_numbers: print str(key+1)+'. '+spacer+item else: print spacer+item if not NO_BACK: print if selection == len(menu_items): #reverse_colour() if show_numbers: print '0. '+left_selector+back_text+right_selector else: print left_selector+back_text+right_selector #text_colour() else: if show_numbers: print '0. '+spacer+back_text else: print spacer+back_text if comment: print print word_wrap(comment) def valid_keys(): """ returns a list of valid responses from get_key() TODO: argument to make only certain key types appear in return """ numbers = ['0','1','2','3','4','5','6','7','8','9'] letters = ['a','A', 'b','B', 'c','C', 'd','D', 'e','E', 'f','F', 'g','G', 'h','H', 'i','I', 'j','J', 'k','K', 'l','L', 'm','M', 'n','N', 'o','O', 'p','P', 'q','Q', 'r','R', 's','S', 't','T', 'u','U', 'v','V', 'w','W', 'x','X', 'y','Y', 'z','Z',] everything_valid = numbers+letters return everything_valid def menu_maker_2(menu_title, menu_items, comment='', item_comments=None, NO_BACK=False, NO_SORT=True, back_text='Back', cursor_pos=0): """ Creates a menu from a title and a list of items that can be operated using the cursor keys """ screen_update_required = True if item_comments == None: item_comments = [comment]*len(menu_items) else: for key in range(len(menu_items)): if key+1 > len(item_comments): item_comments.append(comment) else: if not item_comments[key]: item_comments[key] = comment if not NO_BACK and len(item_comments) < len(menu_items)+1: item_comments.append('Return to previous screen') if not NO_SORT: sorted_items = sort_menu_items(menu_items) menu_items = [] menu_index = [] for item in sorted_items: menu_items.append(item[0]) menu_index.append(item[1]) else: menu_index = [] for key in range(len(menu_items)): menu_index.append(key) menu_index.append(len(menu_items)) show_numbers = False while True: if screen_update_required: print_comment = item_comments[menu_index[cursor_pos]] print_button_menu(menu_title,menu_items,cursor_pos,print_comment,NO_BACK,back_text=back_text,show_numbers=show_numbers) screen_update_required = False key = get_keypress() if key == 'CURSOR_DOWN': if not NO_BACK: if cursor_pos == len(menu_items): cursor_pos = 0 else: cursor_pos +=1 screen_update_required = True elif NO_BACK: if cursor_pos == len(menu_items)-1: cursor_pos = 0 else: cursor_pos += 1 screen_update_required = True elif key == 'CURSOR_UP': if cursor_pos == 0: if not NO_BACK: cursor_pos = len(menu_items) elif NO_BACK: cursor_pos = len(menu_items)-1 else: cursor_pos -= 1 screen_update_required = True elif key =='RETURN': break elif key == 'ESCAPE' and not NO_BACK or \ key == 'BACKSPACE' and not NO_BACK: cursor_pos = -1 break elif key in valid_keys(): if key.isdigit(): if not int(key) > len(menu_items): if NO_BACK and key == '0': pass else: cursor_pos = int(key)-1 break elif key == 'n' or key =='N': if show_numbers: show_numbers = False elif not show_numbers: show_numbers = True screen_update_required = True if cursor_pos == len(menu_items): cursor_pos = -1 if not NO_SORT and cursor_pos != -1: cursor_pos = menu_index[cursor_pos] return cursor_pos def sort_menu_items(menuitems): """ schwartzian(ish) transform of menu items. Return the menu items, plus their original sort order. """ decorated=[] for key, item in enumerate(menuitems): decorated.append([item, key]) decorated.sort() return decorated def get_valid_number(): """ Keep asking the user to enter a number until they do. Then return the number as an integer.""" selection = raw_input('Please enter a number: ') while selection.isdigit() == False: print 'ERROR: "'+selection+'" is not a valid number. Please only enter numbers.\n' selection = raw_input('Please enter a number: ') return int(selection) def print_menu(menutitle, menuitems, comment=None,NO_BACK=False,NO_NUMBERING=False): """Prints a standardised numerical menu, menutitle is a string, menuitems an array of strings. format: qa.print_menu('Menu Title', ['Item 1', 'Item 2', 'Item 3'])""" print '\n','='*len(menutitle) print menutitle print '='*len(menutitle) for item in range(0, len(menuitems)): if NO_NUMBERING: print menuitems[item] else: print str(item+1) + '.', menuitems[item] if not NO_BACK: print '\n0. Back\n' else: print if not comment == None: print word_wrap(comment+"\n") #=============================================================================== #==== Stuff for running external programs ====================================== def auto_run_items(): autorun_events = [] auto_run_fn = settings['defaults']['autorun'] if os.path.exists(auto_run_fn): autorun = open(auto_run_fn,'r') for line in autorun: line = line.rstrip('\n') if line in game_versions: autorun_events.append([game_versions[line]['name'], 'select_game_page', line, 'Let\'s play %s!' % game_versions[line]['name']]) if len(autorun_events) > 0: autorun_events.append(['Main Menu', 'top_menu', 0, 'Return to your normal scheduled QA Menu']) return autorun_events else: return False def run_watson(game_id=None): """ Searches for 'xbwatson.exe'. Prompts the user to close xbwatson if it is found running. Runs watson if it isn't running. """ if game_id == None: watsonpath = settings['defaults']['watsonpath'] watsonprocess = os.path.basename(watsonpath) else: if 'gametype' in game_versions[game_id]: if game_versions[game_id]['gametype'].lower() == 'lan': settingname = 'lanwatson' elif game_versions[game_id]['gametype'].lower() == 'gta_v': settingname = 'gtavwatson' else: settingname = 'watsonpath' else: settingname = 'watsonpath' watsonpath = settings['defaults'][settingname] watsonprocess = os.path.basename(watsonpath) if not os.path.exists(watsonpath): error_exit('Watson not found on local machine') while ProcessRunning(watsonprocess): print 'Attempting to kill Watson...' ## for number in range(3,0,-1): ## print str(number)+'... ', ## time.sleep(1) KillAllTaskName(watsonprocess) time.sleep(0.1) #watsonrunning = find_running_process(watsonprocess) subprocess.Popen(watsonpath) def run_rag_and_rfs(game_id=None): """ looks for rag and rfs, if they aren't running, runs them. """ if game_id == None: ragpath = settings['defaults']['ragpath'] rfspath = settings['defaults']['rfspath'] else: if 'gametype' not in game_versions[game_id]: ragpath = settings['defaults']['ragpath'] rfspath = settings['defaults']['rfspath'] elif game_versions[game_id]['gametype'].lower() == 'jimmy' or \ game_versions[game_id]['gametype'].lower() == 'rdr2': ragpath = settings['defaults']['jimmyrag'] rfspath = settings['defaults']['jimmyrfs'] elif game_versions[game_id]['gametype'].lower() == 'gta_v': ragpath = settings['defaults']['gtavrag'] rfspath = settings['defaults']['gtavrfs'] else: ragpath = settings['defaults']['ragpath'] rfspath = settings['defaults']['rfspath'] if not os.path.exists(ragpath): error_exit('RAG not found on local machine, looked in: '+ragpath) if not os.path.exists(rfspath): error_exit('SystrayRFS not found on local machine,' 'looked in: '+rfspath) ragprocess = os.path.basename(ragpath) rfsprocess = os.path.basename(rfspath) while ProcessRunning(ragprocess): print 'Killing RAG' KillRag() if ProcessRunning(rfsprocess): print 'Killing RFS' KillAllTaskName(rfsprocess) subprocess.Popen(ragpath) subprocess.Popen([rfspath, '-trusted']) def DoLaunchPreparations(game_id): game = game_versions[game_id] if 'init_copy_folder' in game: print 'init_copy_folder found, doing folder copy' FancyCopyFolder(game['init_copy_folder'][0], game['init_copy_folder'][1]) if 'write_ip' in game: print 'Attempting to write ip address to file...' WriteIPToFile(game_versions[game_id]['write_ip']) if 'write_switches' in game: print 'Attempting to write switches to file...' print game['gametype'] print 'separator: "%s"' % GetCommandLineSeparator(game['gametype']) if 'lan_dlc_disabled' in game_versions[game_id]: switches = GetLANSwitches(game_id) else: if 'switches' in game_versions[game_id]: switches = game['switches'] else: switches = [] if 'add_switches' in game_versions[game_id]: switches.extend(game_versions[game_id]['add_switches']) WriteSwitches(game['write_switches'], switches, GetCommandLineSeparator(game['gametype'])) def launch_gta_iv(game_id, switches=None): """ do all the things the old batfile did before running the game """ DoLaunchPreparations(game_id) if 'init_copy_folder' in game_versions[game_id]: print 'init_copy_folder found, doing folder copy' FancyCopyFolder(game_versions[game_id]['init_copy_folder'][0], game_versions[game_id]['init_copy_folder'][1]) #game specific settings game_setting = False #Don't forget: game_setting is used by the switches section if 'gametype' in game_versions[game_id]: game_setting = game_versions[game_id]['gametype'].lower() if game_setting == 'gtaiv': map_ext = 'map' folder = 'xE:\\gta4_2005\\' movie_destination = folder+'xbox360\\movies\\' GetIVxex(game_versions[game_id]) elif game_setting == 'rdr2': map_ext = 'cmp' folder = 'xE:\\rdr2\\' movie_destination = folder elif game_setting == 'jimmy': map_ext = 'cmp' folder = 'xE:\\jimmy\\' movie_destination = folder+'xbox360\\movies\\' elif game_setting == 'gta_v': map_ext = 'cmp' folder = 'xE:\\game\\' else: #default to gta4 settings, just incase map_ext = 'map' folder = 'xE:\\gta4_2005\\' movie_destination = folder+'xbox360\\movies\\' else: #default to gta4 settings if no 'game' entry is found for this gameid map_ext = 'map' folder = 'xE:\\gta4_2005\\' movie_destination = folder+'xbox360\\movies\\' GetIVxex(game_versions[game_id]) wait_for_xbox() #check_script_warning(game_id) <-- nobody keeping scripts up to date, removed if 'cab_folder_source' in game_versions[game_id] and \ 'cab_folder_destination' in game_versions[game_id]: if not using_latest_cab_file(game_id): items = [] items.append(['Skip Transfer', 'final_event', 'skip', 'Continue to load %s without transferring CAB' % game_versions[game_id]['name']]) items.append(['Transfer CAB', 'final_event', 'transfer', 'Transfer the CAB file on your pc to the 360']) selection = MiniMenu('CAB file mismatch detected',items) if selection == 'skip': pass elif selection == 'transfer': cab_transfer(game_id) elif selection == '_BACK': return False xdk_vars() #get temp location from environment variables temp = os.environ.get('temp') xex = game_versions[game_id]['xex'] mapfile = xex.rsplit('.')[0]+'.'+map_ext #Check if 'folder' is a file, erase if it is. if len(xbdir_list(folder)) <= 1: XBDel(folder.strip('\\')) backup_pstats(game_id) run_rag_and_rfs(game_id) run_watson(game_id) #copy xex and map files to console XBCopy(xex,folder) XBCopy(mapfile,folder) #hack in movie copying support if 'movie_source' in game_versions[game_id]: print '\n\nCopying movies, this may take some time...\n' movies = game_versions[game_id]['movie_source']+'\\*.bik' XBCopyTree(movies, movie_destination, newer_only=True) ## if switches is None: ## switches = '' ## if 'switches' in game_versions[game_id]: ## for item in game_versions[game_id]['switches']: ## switches = switches+' '+item if switches is None: switches = ' ' if 'switches' in game_versions[game_id]: switch_list = game_versions[game_id]['switches'] for switch in switch_list: switches += switch+' ' if 'lan_dlc_disabled' in game_versions[game_id]: switch_list = GetLANSwitches(game_id) switches = ' ' for switch in switch_list: switches += switch+' ' if 'add_switches' in game_versions[game_id]: for switch in game_versions[game_id]['add_switches']: switches += switch+' ' if 'gametype' in game_versions[game_id]: if game_versions[game_id]['gametype'] == 'gta_v': if 'write_switches' in game_versions[game_id]: switches = '"@%s"' % game_versions[game_id]['write_switches'] #special rule for RDR cos it needs 50 bazillion command line switches if game_setting == 'rdr2': if 'rdr_cmd_txt' in game_versions[game_id]: rdr_cmd_txt = game_versions[game_id]['rdr_cmd_txt'] else: rdr_cmd_txt = 'X:\\rdr2\\build\\commandline.txt' rdr_commandlines(game_id,'x:\\rdr2\\rdr_cmd.txt',rdr_cmd_txt) switches = '@x:\\rdr2\\rdr_cmd.txt' #os.chdir(os.path.dirname(xex)) <-- don't think i need to do this delete_logs(game_id) #copy rfs.dat across XBCopy(temp+'\\rfs.dat',folder) logging('launch_gta_iv: xbReboot /w '+folder+os.path.basename(xex)+' '+switches) os.system('xbReboot /w '+folder+os.path.basename(xex)+' '+switches) def launch_ps3(game_id, switches=None): """ Launch a game on PS3. Requires a 'self' setting in game_id """ DoLaunchPreparations(game_id) if 'init_copy_folder' in game_versions[game_id]: print 'init_copy_folder found, doing folder copy' FancyCopyFolder(game_versions[game_id]['init_copy_folder'][0], game_versions[game_id]['init_copy_folder'][1]) if not target_manager_installed(): error_exit('TargetManager appears to not be installed, PS3 requires' ' TargetManager') if not ProcessRunning('ps3tm.exe'): run_targetmanager() #shut down any versions of ps3run, to close any PSNotsons print 'Shutting down ps3runs to close PSNotsons...' KillAllTaskName('ps3run.exe') ps3run = os.path.join(os.path.join(os.getenv('SN_PS3_PATH'),'bin'), 'ps3run.exe') ps3run = '"'+ps3run+'"' if 'write_ip' in game_versions[game_id]: print 'Attempting to write ip address to file...' WriteIPToFile(game_versions[game_id]['write_ip']) if 'homedir' in game_versions[game_id]: print 'Attempting to set home directory...' homedir = game_versions[game_id]['homedir'] os.system(ps3run+' -h '+homedir) if 'fileserv' in game_versions[game_id]: print 'Attempting to set fileserv directory...' fileserv = game_versions[game_id]['fileserv'] os.system(ps3run+' -f '+fileserv) self = game_versions[game_id]['self'] ## if switches is None: ## switches = ' ' ## if 'switches' in game_versions[game_id]: ## switch_list = game_versions[game_id]['switches'] ## ## if 'lan_dlc_disabled' in game_versions[game_id]: ## switch_list = GetLANSwitches(game_id) ## ## for switch in switch_list: ## switches += switch+' ' if switches is None: switches = ' ' if 'switches' in game_versions[game_id]: switch_list = game_versions[game_id]['switches'] for switch in switch_list: switches += switch+' ' if 'lan_dlc_disabled' in game_versions[game_id]: switch_list = GetLANSwitches(game_id) switches = ' ' for switch in switch_list: switches += switch+' ' if 'add_switches' in game_versions[game_id]: for switch in game_versions[game_id]['add_switches']: switches += switch+' ' if 'gametype' in game_versions[game_id]: if game_versions[game_id]['gametype'] == 'gta_v': if 'write_switches' in game_versions[game_id]: switches = '"@%s"' % game_versions[game_id]['write_switches'] backup_pstats(game_id) delete_logs(game_id) if 'gametype' in game_versions[game_id]: if game_versions[game_id]['gametype'].lower() != 'lan': run_rag_and_rfs(game_id) else: run_rag_and_rfs(game_id) print '\n\nAttempting to reboot PS3...' logging('launch_ps3: command: '+ps3run+' -r '+self+' '+switches) ps3runner = subprocess.Popen(ps3run+' -r '+self+' '+switches, stdout=subprocess.PIPE) error_message = 'failed' response = ps3runner.communicate()[0] if error_message in response.lower(): print '\n\nERROR:' print word_wrap('No response from PS3! Please check that TargetManager ' 'is running, and you are connected to your PS3!\n\n' 'TargetManager Says: %s\n\n' 'Press any key to return to Game Page.' % response) wait_for_key() return False run_notson(game_id) def WriteIPToFile(fname): try: ipfile = open(fname, 'w') except IOError: error_exit('Unable to open %s for writing IP' % fname) ip = socket.gethostbyname(socket.gethostname()) ipfile.write('%s' % ip) ipfile.close() def run_targetmanager(): tm_path = os.path.join(os.getenv('SN_PS3_PATH'), os.path.join('bin','ps3tm.exe')) tm_path = '"'+tm_path+'"' subprocess.Popen(tm_path) def run_notson(game_id): logfolder = os.path.dirname(game_versions[game_id]['self']) #os.system('start PSNotson.py '+logfolder) #command: "start "window title" "notson path" "logs folder" os.system('start "%s" "%s" "%s"' % ( settings['defaults']['notson_title'], settings['defaults']['psnotson'], logfolder)) def target_manager_installed(): ps3run = os.path.join('bin','ps3run.exe') if os.getenv('SN_PS3_PATH'): if os.path.exists(os.path.join(os.getenv('SN_PS3_PATH'),ps3run)): return True else: return False else: return False def get_paths(): unsplit_paths = os.getenv('path') paths = unsplit_paths.split(';') return paths def xdk_vars(): xedk = os.getenv('xedk') path = os.getenv('path') os.putenv('PATH',xedk+'\\bin\\win32;'+path+';') def generate_date_foldername(): """ use the current date/time to generate a string that can be used as a foldername """ foldername = time.strftime('%Y-%m-%d %H-%M-%S') return foldername def date_from_file(filename): if not os.path.exists(filename): error_exit('date_from_file(): File for generating foldername does not exist') modtime = os.path.getmtime(filename) modtime = time.localtime(modtime) return time.strftime('%Y-%m-%d %H-%M-%S',modtime) def backup_pstats(game_id): """ backup existing pstats to a local folder """ logging('backup_pstats() called for '+game_id) if 'logsource' not in game_versions[game_id]: logging('No logsource found for %s' % game_id) return False #logging('backup_pstats() called for '+game_id) print '\nBacking up pstats files...' backup_location = settings['defaults']['pstats_backup'] if not os.path.exists(backup_location): os.makedirs(backup_location) logsources = game_versions[game_id]['logsource'] log_file_paths = [] for logsource in logsources: for log_path in directory_list(logsource,'*.pstats'): if log_path not in log_file_paths: log_file_paths.append(log_path) for mod_path in log_file_paths: newest_file = 0 if os.path.getmtime(mod_path) > newest_file: newest_file = mod_path if len(log_file_paths) == 0: print ' none found' return False backup_location_final = os.path.join(backup_location, date_from_file(newest_file)) if not os.path.exists(backup_location_final): os.makedirs(backup_location_final) for path in log_file_paths: destination = os.path.join(backup_location_final,os.path.basename(path)) if os.path.exists(destination): add_number = 1 split_dest = os.path.splitext(destination) while os.path.exists(split_dest[0]+' ('+str(add_number)+')'+split_dest[1]): add_number += 1 destination = split_dest[0]+' ('+str(add_number)+')'+split_dest[1] print path logging('backup_pstats() attempting to move: '+path+' to '+destination) try: shutil.copy2(path, destination) except IOError: error_exit('IOError in backup_pstats()') print '... complete' def delete_logs(game_id): """ deletes logs and dmps using the stuff laid out in game_versions""" if 'logfiles' not in game_versions[game_id]: if 'xex' not in game_versions[game_id]: logpath = os.environ.get('RAGE_CRASHDUMP_DIR') if logpath == None: logpath = 'x:\\gta\\build\\' else: logpath = os.path.dirname(game_versions[game_id]['xex']) if os.path.exists(logpath): os.chdir(logpath) os.system('erase *.log') os.system('erase *.dmp') return True else: return False for location in game_versions[game_id]['logsource']: for filename in game_versions[game_id]['logfiles']: logging('delete_logs: %s triggered erase of %s files in %s' % (game_id, filename, location)) if os.path.exists(location): logging('erasing %s' % os.path.join(location, filename)) os.system('erase '+os.path.join(location,filename)) if 'homedir' in game_versions[game_id]: for fname in FindPS3Dumps([game_versions[game_id]['homedir']]): os.remove(fname) return True def cab_transfer(game_id): """ replacing old cab transfer.py and it's over-complexity """ wait_for_xbox() xdk_vars() cab_folder_source = game_versions[game_id]['cab_folder_source'] cab_folder_destination = game_versions[game_id]['cab_folder_destination'] rpf_data_destination = 'devkit:\\gta4_2005' #should maybe replace this with something in game_versions comment = ('If you continue, this will transfer or overwrite the %s cab ' 'file without erasing any other CABs on the 360' % game_versions[game_id]['name']) if not os.path.exists(os.path.dirname(cab_folder_source)): error_exit('Unable to find CAB file: '+cab_folder_source) #try and prevent uploading to a folder that's actually a filename if os.path.basename(cab_folder_source) == os.path.basename(cab_folder_destination): if os.path.isfile(cab_folder_source): cab_folder_destination = os.path.dirname(cab_folder_destination) files_on_360 = xbdir_list(cab_folder_destination) if len(files_on_360) > 0: items = [] items.append(['Erase CABs', 'final_event', 'erase', 'Erase existing CAB files before transferring the new CAB file over']) items.append(['Continue', 'final_event', 'continue', 'Transfer new CAB without erasing old CAB']) selection = MiniMenu('Existing CAB files found',items,NO_BACK=True) if selection == 'continue': pass elif selection == 'erase': for cab_filename in files_on_360: print 'Erasing:',cab_folder_destination.strip('\\')+'\\'+cab_filename[0] #os.system('xbdel /f '+cab_folder_destination.strip('\\')+'\\'+cab_filename[0]) XBDel(cab_folder_destination.strip('\\')+'\\'+cab_filename[0]) #delete and remake the cab folder destination and rpf destination ## os.system('xbdel /r /f "HDD:\\$TitleUpdate"') ## os.system('xbdel /r /f "'+cab_folder_destination+'"') print_slow_dots() mkdir_error = os.system('xbmkdir "'+cab_folder_destination+'"') if mkdir_error == 1: #print 'making folders' split_destination = cab_folder_destination.split('\\') walking_path = '' for path_part in split_destination: if path_part.endswith(':'): path_part += '\\' walking_path = os.path.join(walking_path,path_part) #print walking_path #os.system('xbmkdir "'+walking_path+'"') ## os.system('xbdel /r /f "'+rpf_data_destination+'"') print_slow_dots() ## os.system('xbmkdir "'+rpf_data_destination+'"') #copy rfs.dat file across #XBCopy(os.getenv('temp')+'\\rfs.dat',rpf_data_destination) print '\n\nCopying CAB files, this may take some time\n\n' XBCopyTree(cab_folder_source,cab_folder_destination) print '\n\nCAB Transfer Complete!\n' print 'Press any key to continue' wait_for_key() return True def using_latest_cab_file(game_id): """Uses xbdir to determine the modified dates of a pair of files or folders and returns True if all files appearing on the xbox folder also appear in the cab_folder_source, and the modified dates match.""" if 'no_cab_check' in game_versions[game_id]: return True wait_for_xbox() #xbdir = '"C:\\Program Files\\Microsoft Xbox 360 SDK\\bin\\win32\\xbdir.exe"' xbdir = '"%s\\xbdir.exe"' % settings['defaults']['360sdk'] xbox_dir = subprocess.Popen(xbdir+' "'+game_versions[game_id]['cab_folder_destination'] +'"', stdout=subprocess.PIPE, universal_newlines=True) network_dir = subprocess.Popen(xbdir+' "'+game_versions[game_id]['cab_folder_source'], stdout=subprocess.PIPE, universal_newlines=True) xbox_files = format_xbdir_output(xbox_dir.communicate()[0]) network_files = format_xbdir_output(network_dir.communicate()[0]) if len(xbox_files) != len(network_files): return False #see which filenames appearing in xbox_files match any filenames appearing in network_files filename_matches = {} #[None]*len(xbox_files) for pos, file_info in enumerate(xbox_files): for net_pos, net_file_info in enumerate(network_files): if file_info[0] == net_file_info[0]: filename_matches[pos] = net_pos #compare the matching files file_matches = {} for pos, net_pos in filename_matches.iteritems(): file_match = True for e_pos, file_info in enumerate(xbox_files[pos]): if file_info != network_files[net_pos][e_pos]: file_match = False if file_match: file_matches[xbox_files[pos][0]]=True if not file_match: file_matches[xbox_files[pos][0]]=False if len(file_matches) is 0: return False all_match = True for filename,valid in file_matches.iteritems(): if not valid: all_match = False return all_match def xbdir_list(target,directories=False): wait_for_xbox() """ Returns formatted directory list for a directory (for xbox, but works for pc as well """ #xbdir = '"C:\\Program Files\\Microsoft Xbox 360 SDK\\bin\\win32\\xbdir.exe"' xbdir = '"%s\\xbdir.exe"' % settings['defaults']['360sdk'] xbox_dir = subprocess.Popen(xbdir+' "'+target+'"', stdout=subprocess.PIPE, universal_newlines=True) formatted = format_xbdir_output(xbox_dir.communicate()[0]) final_list = [] for item in formatted: if item[3] == directories: final_list.append(item) return final_list #formatted def format_xbdir_output(output,directories=False): """ format output from xbdir to associate filenames with edited dates. returns a list full of lists. 0: Year 1: Month 2: Day 3: Hour 4: Minute 5: Filename 6: filesize 7: directory? (if true, it's a file, if false, it's a directory) """ list_out = output.split('\n') file_info = [] for line in list_out: current = [None]*4 if len(line) > 28: if line[0].isdigit(): #filename current[0] = line[39:].rstrip('\n') #filesize if line[24:29] == '': current[1] = 0 else: current[1] = int(line[18:38].replace(',','').strip()) #modified date in seconds since the epoch time_line = line[0:18]+'m' if time_line[12:14] == '00': time_line = time_line[:11]+'12'+time_line[14:] current[2]=time.mktime(time.strptime(time_line,'%m/%d/%Y %I:%M%p')) #print 'stored time',current[1] #file or directory? if line[24:29] == '': current[3] = True else: current[3] = False #time test ## timestring = line[0:18]+'m' ## print timestring, ## utime = time.strptime(timestring,'%m/%d/%Y %I:%M%p'), ## print utime[0], ## print time.strftime('%m/%d/%Y %I:%M%p',utime[0]) ## print time.mktime(utime[0]), ## print time.ctime(time.mktime(utime[0])) ## ## ## raw_input() file_info.append(current) return file_info def prepare_for_emulation(game_id): """transfer cab file and titleupdate to default xbox""" title_update_dest = 'HDD:\\$TitleUpdate' title_update_source = game_versions[game_id]['title_update'] #abandon ship if the titleupdate source can't be found if not os.path.exists(title_update_source): error_exit('$TitleUpdate could not be found. Please check '+title_update_source) #do a regular cab transfer, if we have a cab file if 'cab_folder_source' in game_versions[game_id]: if not cab_transfer(game_id): print 'Cancelled...' return False xdk_vars() #destroy old titleupdate folder #os.system('xbdel /r /f "'+title_update_dest+'"') XBDel(title_update_dest) print '\nCopying $TitleUpdate...' #copy titleupdate XBCopyTree(title_update_source,title_update_dest) print '\n\nXBox is now ready for use with Disc Emulator' print '\nPress any key to return to menu' wait_for_key() #=============================================================================== #==== File Updating Stuff ====================================================== def update_sync_ini(): """ Updates the local Synchronize It! profile with an ini file from the network, if the file on the network has a newer 'modified on' date. Locations of the two files are retrieved from game_versions.ini""" for switch in command_line_switches(): if switch == '-focus': print 'skipping sync ini update' return False localfile = settings['defaults']['syncitlocal'] remotefile = settings['defaults']['syncitremote'] if os.path.exists(localfile) and os.path.exists(remotefile): files_match = filecmp.cmp(localfile, remotefile) else: files_match = True #oh god this is a horrible way of doing this, rewrite it immediately if not files_match: selection = 1 if selection == 1: try: shutil.copy2(remotefile, localfile) logging('Updating Synchronize It! profile.') except IOError: print 'ERROR: Problem updating sync ini, local file may not exist.' logging('Problem updating sync ini, local file may not exist, or may be in use.','ERROR') time.sleep(0.5) return True return False def check_menu_update(): """ Checks the local qa menu files against remote qa menu files, tells the user to update (how will they update?) if the remote files are newer. """ for switch in command_line_switches(): if switch == '-focus': print 'skipping menu update' return False local = settings['defaults']['qamenulocal'] remote = settings['defaults']['qamenuremote'] menufiles = settings['defaults']['qamenufiles'] menunotfound = 0 if not os.path.exists(local): print 'ERROR: QA Menu not found in '+local+' please rerun installer script', print_slow_dots(5) menunotfound += 1 if not os.path.exists(remote): print 'ERROR: QA Menu update files not found in '+remote, print_slow_dots(5) menunotfound += 1 files_updated = 0 updaterequired = 0 filenames_updated = [] if menunotfound == 0: for filename in menufiles: localpath = os.path.join(local,filename) remotepath = os.path.join(remote,filename) if not os.path.exists(localpath) and os.path.exists(remotepath): shutil.copy2(remotepath, localpath) logging('Created file '+localpath+' from '+remotepath) files_updated += 1 filenames_updated.append(filename) elif update_file_if_different(localpath, remotepath) == True: files_updated += 1 logging('Updated file '+localpath+' from '+remotepath) filenames_updated.append(filename) #time.sleep(0.5) ## if settings_update_required() == True: ## settingsfile = 'settings.ini' ## shutil.copy2(os.path.join(remote, settingsfile),os.path.join(local,settingsfile)) ## logging('Updated file '+os.path.join(local,settingsfile)+' from '+os.path.join(remote, settingsfile)) ## files_updated += 1 ## filenames_updated.append(settingsfile) ## settings_updated = True ## else: ## settings_updated = False if files_updated > 0: os.system('cls') print 'The following file(s) succesfully updated:' for filename in filenames_updated: print ' '*3, filename ## if settings_updated: ## print word_wrap('\nSORRY: The settings.ini file had to be updated, meaning you will have been returned to default settings. I apologise!') print '\n' print_changes() error_exit('\nComponents updated, please restart QA Menu!') ##def update_file_if_newer(localfile, remotefile): ## """ checks localfile against remotefile, if remotefile is newer it ## attempts to overwrite localfile with remotefile. Returns true if ## the file is updated succesfully""" ## ## file_updated = False ## if is_file2_newer(localfile, remotefile): ## try: ## shutil.copy2(remotefile,localfile) ## #print os.path.basename(remotefile)+' update succesful!' ## file_updated = True ## #time.sleep(2) ## except IOError: ## print '\nERROR: Please make sure '+localfile+' is not in use or write protected' ## raw_input('\nPress ENTER to continue without update') ## return file_updated def update_file_if_different(localfile, remotefile): """ checks localfile against remotefile, if remotefile is different it attempts to overwrite localfile with remotefile. Returns true if the file is updated succesfully""" file_updated = False if not os.path.exists(remotefile): error_exit(remotefile+' not found.') if not filecmp.cmp(localfile, remotefile): try: shutil.copy2(remotefile,localfile) #print os.path.basename(remotefile)+' update succesful!' file_updated = True #time.sleep(2) except IOError: print '\nERROR: Please make sure '+localfile+' is not in use or write protected' raw_input('\nPress ENTER to continue without update') return file_updated def is_file2_newer(file1,file2): """ Returns True if file2 is newer than file1. Prints an error and returns False if either file is missing """ if os.path.exists(file1): file1found = True else: file1found = False file2_is_newer = False print 'ERROR: Attempting to compare two files, unable to find '+file1 time.sleep(0.5) if os.path.exists(file2): file2found = True else: file2found = False file2_is_newer = False print 'ERROR: Attempting to compare two files, unable to find '+file2 time.sleep(0.5) if file1found and file2found: if int(os.path.getmtime(file1)) < int(os.path.getmtime(file2)): file2_is_newer = True elif os.path.getmtime(file1) == os.path.getmtime(file2): file2_is_newer = False else: file2_is_newer = False return file2_is_newer def print_changes(number_of_changes = 1): """ Prints changes found in the changes log on the network. Prints only the number of changes supplied (one "change" is determined by the date in brackets above the changes from that day). By default, only prints the latest change. If number_of_changes is 0, prints all changes found.""" if not os.path.exists('N:\\RSGEDI\\QA\\QA Menu\\changes.txt'): return False changes_file = open('N:\\RSGEDI\\QA\\QA Menu\\changes.txt') brackets_found = 0 changes = [] for line in changes_file: if line.startswith('['): brackets_found += 1 changes.append(line) else: if line != '\n': changes[brackets_found-1] += line if number_of_changes == 0: for line in changes: print line else: changes_printed = 0 for line in changes: print line changes_printed += 1 if changes_printed == number_of_changes: break return True ##def settings_update_required(): ## """ checks the local settings.ini file with the one on the network. ## if the remote file has any settings that the local file does, ## return True""" #### remote_settings_file = os.path.join(get_setting('defaults','qamenuremote'),'settings.ini') #### remote_defaults = load_settings(remote_settings_file) #### #### local_settingnames = [] #### remote_settingnames = [] #### for name in defaults: #### local_settingnames.append(name) #### for name in remote_defaults: #### remote_settingnames.append(name) #### ###### if len(local_settingnames) != len(remote_settingnames): ###### print 'mismatch length' ###### update_required = True ###### else: #### missing_from_local = 0 #### for name in remote_settingnames: #### if name not in local_settingnames: #### missing_from_local += 1 #### if missing_from_local > 0: #### update_required = True #### if missing_from_local == 0: #### update_required = False #### #### return update_required ## return False #=============================================================================== #====Log Uploader=============================================================== def upload_logs(game_id): """ User interface for all the log copying stuff. Uses settings found in game_id in game_versions.ini """ if not os.path.exists(game_versions[game_id]['logdestination']): error_exit('upload_logs: log destination does not exist') if 'multiplayer' in game_versions[game_id]['logdestination'].lower(): multiplayer = True elif 'singleplayer' in game_versions[game_id]['logdestination'].lower(): multiplayer = False else: selection = menu_maker_2('Singleplayer or Multiplayer',['Singleplayer','Multiplayer'],'Were you playing a single player game, or a multiplayer game?\n\nNOTE: Multiplayer option left in for legacy. If playing multiplayer, please use MPLogGrabber instead.',NO_BACK=True) if selection == 0: multiplayer = False elif selection == 1: multiplayer = True files_with_console = [] for location in game_versions[game_id]['logsource']: files_with_console += directory_list(location,'console') #print files_with_console if len(files_with_console) > 0: files_with_console_and_log = [] for filename in files_with_console: if filename.endswith('log'): files_with_console_and_log.append(filename) elif len(files_with_console) < 1: files_with_console_and_log = [] if len(files_with_console_and_log) < 1: username = raw_input('Enter your profile name: ') else: usernames =[] for filename in files_with_console_and_log: usernames += get_profile_name_from_log(filename) final_usernames = [] for name in usernames: if not name in final_usernames: final_usernames.append(name) if len(final_usernames) > 1: selection = menu_maker_2('Select a Profile Name',final_usernames,'Multiple profile names were found, please choose the correct profile name',NO_BACK=True) username = final_usernames[selection] else: if len(final_usernames) == 0: username = raw_input('Enter your profile name: ') else: username = final_usernames[0] if multiplayer == True: playertype = client_or_host(game_id) if not playertype: selection = menu_maker_2('Host or Client?',['Host','Client'],'Were you the host or a client in that game?',NO_BACK=True) if selection == 0: host_or_client = 'host' if selection == 1: host_or_client = 'client' else: host_or_client = playertype else: host_or_client = '' print '\n\nProfile Name:',username if host_or_client: print '\n Playertype:', host_or_client.upper() print '\nWhat folder should the logs be sent to?\n' print box_text('WARNING: Please only use valid bug numbers for folder names. ' 'If you do not have a valid bug number yet, make sure you remember ' 'to come back and rename the folder to match the bug number.\n\n' 'IF YOU FORGET, BRIAN WILL FIND YOU AND HE WILL TAKE YOUR EYES.', 1) bugnumber = raw_input('Enter a bug number or destination folder: ') log_folder = os.path.join(game_versions[game_id]['logdestination'], bugnumber) if host_or_client == '': log_destination = os.path.join(log_folder,username) else: log_destination = os.path.join(log_folder,username+' ('+host_or_client+')') while os.path.exists(log_destination) or bugnumber == '': if bugnumber == '': print '\nERROR: Blank destination folder entered. Please enter a destination folder' else: print '\nERROR: Log destination \''+log_destination+'\' already exists.' bugnumber = raw_input('\nPlease enter a new bugnumber or foldername: ') log_folder = os.path.join(game_versions[game_id]['logdestination'], bugnumber) if host_or_client == '': log_destination = os.path.join(log_folder,username) else: log_destination = os.path.join(log_folder,username+' ('+host_or_client+')') file_list = list_of_logfiles(game_versions[game_id]['logsource'], game_versions[game_id]['logfiles']) #copy_files(file_list,log_destination) if not os.path.exists(log_destination): os.makedirs(log_destination) if 'homedir' in game_versions[game_id]: rardest = os.path.join(log_destination, 'ps3core.rar') dumps = FindPS3Dumps([game_versions[game_id]['homedir']]) if len(dumps) > 0: print 'Compressing PS3 Dump...' RARfile(dumps, rardest) else: print 'No PS3 Dump files found' FancyCopyFiles(file_list, log_destination) print '\nLogs Copied! Hooray!' print 'All logs copied to', log_destination friendly_file_list = 'Files uploaded to:\n"'+log_destination+'"\n\n' for fname in file_list: friendly_file_list += ' + '+os.path.basename(fname)+'\n' items = [] items.append(['Continue to game page', 'final_event', 'continue', friendly_file_list]) items.append(['Open logs folder', 'final_event', 'logs_folder', 'Open log destination folder']) while True: selection = MiniMenu('Logs copied!',items,NO_BACK=True) if selection == 'logs_folder': try: os.startfile(log_destination) except WindowsError: ## error_exit('Open Logs Folder tried to open a logs folder that ' ## 'does not exist.') print word_wrap('ERROR: Open logs folder tried to open a logs ' 'folder that does not exist.\n\nPress any ' 'key to continue.') wait_for_key() elif selection == 'continue': break return True def directory_list(directory, extension=None): """ Gives a list of files present in the directory provided. If "extension" is supplied, lists only files with that string present in the filename. """ if not os.path.exists(directory): return [] files = os.listdir(directory) if extension == None: return files files_with_extension = [] for filename in files: if extension.strip('*') in filename: files_with_extension.append(os.path.join(directory,filename)) return files_with_extension def copy_files(file_list,destination): """ copies the list of files in file_list to 'destination'""" if not os.path.exists(destination): os.makedirs(destination) for filename in file_list: destinationpath = os.path.join(destination,os.path.basename(filename)) if not os.path.exists(destinationpath): print 'Copying \''+os.path.basename(filename)+'\' to \''+destination+'\'' shutil.copy2(filename, destinationpath) else: ## print 'Overwriting \''+destinationpath+'\'' ## os.remove(destinationpath) ## shutil.copy2(filename, destinationpath) add_number = 0 destinationpath_plus = destinationpath while os.path.exists(destinationpath_plus): add_number += 1 split_dest = os.path.splitext(destinationpath) destinationpath_plus = split_dest[0]+' ('+str(add_number)+')'+split_dest[1] logging('Copying "%s" to "%s"'% (filename,destinationpath_plus)) shutil.copy2(filename,destinationpath_plus) def list_of_logfiles(logsources,files): """ returns a list of files that match the filenames/wildcards present in 'files' """ #if not os.path.exists(source): #return None logfiles = [] for source in logsources: for filename in files: if not filename.startswith('*.'): if os.path.exists(os.path.join(source,filename)): logfiles.append(os.path.join(source,filename)) if filename.startswith('*.'): for valid_file in directory_list(source,filename): logfiles.append(os.path.join(source,valid_file)) return logfiles def get_profile_name_from_log(location): """ Searches for a console log in the location provided, then tries to find a profile name inside the log. Returns a list of all profile names """ #if not os.path.exists(location): #return None console_log_file = open(location) username_lines = [] for line in console_log_file: if 'Gamer:' in line and 'SIGNED' in line: #username_line = line username_lines.append(line) usernames = [] for line in username_lines: usernames.append(clean_profile_line(line)) return usernames def clean_profile_line(line): """ Returns a cleaned up profile name from a line found in a console log """ ## profile_start = line.find('"') ## profile_end = line.rfind('"') ## ## username = line[profile_start+1:profile_end] regex = re.compile('(?<=Gamer:")[^"]+(?=")') username = regex.findall(line) return username[0] #====General Stuff============================================================== def get_keypress(): """read the keybuffer, return a key if there's one in there""" key = '' special_key = False if not msvcrt.kbhit(): return False key = msvcrt.getch() if key == '\000' or key == '\xe0': special_key = True key = msvcrt.getch() #special case for non-special special buttons if ord(key) == 27: key = 'ESCAPE' elif ord(key) == 13: key = 'RETURN' elif ord(key) == 9: key = 'TAB' elif ord(key) == 8: key = 'BACKSPACE' if special_key: key = translate_special_key(key) #logging(key,'TEST') #<-- that'll pipe everything typed straight into log return key def translate_special_key(key): """Translate letters into their special-key equivalent.""" ord_key = ord(key) #cursor keys if ord_key == 75: return_key = 'CURSOR_LEFT' elif ord_key == 77: return_key = 'CURSOR_RIGHT' elif ord_key == 80: return_key = 'CURSOR_DOWN' elif ord_key == 72: return_key = 'CURSOR_UP' #home bank elif ord_key == 82: return_key = 'INSERT' elif ord_key == 83: return_key = 'DELETE' elif ord_key == 71: return_key = 'HOME' elif ord_key == 79: return_key = 'END' elif ord_key == 73: return_key = 'PAGE_UP' elif ord_key == 81: return_key = 'PAGE_DOWN' #function keys elif ord_key == 59: return_key = 'F1' elif ord_key == 60: return_key = 'F2' elif ord_key == 61: return_key = 'F3' elif ord_key == 62: return_key = 'F4' elif ord_key == 63: return_key = 'F5' elif ord_key == 64: return_key = 'F6' elif ord_key == 65: return_key = 'F7' elif ord_key == 66: return_key = 'F8' elif ord_key == 67: return_key = 'F9' elif ord_key == 68: return_key = 'F10' elif ord_key == 133: return_key = 'F11' elif ord_key == 134: return_key = 'F12' else: return_key = key return return_key def wait_for_key(): while True: key = get_keypress() if key != False: break else: time.sleep(0.5) return key def clear_key_buffer(): key = get_keypress() while key != False: key = get_keypress() def error_exit(quitmessage=None, log=True): """ quits with the supplied error message. if no message is supplied prints with some basic debug information """ if quitmessage == None: caller_name = sys._getframe(1).f_code.co_name print 'An error occured in',caller_name if log: logging('An error occured in'+caller_name,'ERROR') else: print word_wrap('ERROR: '+quitmessage) if log: logging(quitmessage.replace('\n',' '),'ERROR') print '\nPress any key to exit' selection = wait_for_key() if selection == '1': caller_name = sys._getframe(1).f_code.co_name print 'An error occured in',caller_name traceback.print_stack() #wait_for_key() sys.exit() def print_slow_dots(number=3,speed=0.3): """ prints a sequence of dots one at a time with a gap of speed ms between the dots. if you want it to follow a statement, do like this: print 'waiting', #note the comma print_slow_dots() """ dots_printed = 0 while dots_printed != number: print '. ', dots_printed += 1 time.sleep(speed) def box_text(text='',boxtype=0): """ Print text in a box made of ascii characters, length determined by longest line in 'text', or word wrapped to 79 chars. boxtypes: 0 = single line 1 = double line 2 = blocks """ single_line = [chr(218), chr(196), chr(191), chr(179), chr(179), chr(192), chr(196), chr(217)] double_line = [chr(201), chr(205), chr(187), chr(186), chr(186), chr(200), chr(205), chr(188)] blocks = [chr(219), chr(223), chr(219), chr(219), chr(219), chr(219), chr(220), chr(219)] splodge = [chr(219)]*8 if boxtype == 0: elements = single_line elif boxtype == 1: elements = double_line elif boxtype == 2: elements = blocks else: elements = splodge #print text text = word_wrap(text,74) #print text text_l = text.splitlines() box_height = len(text_l) box_width = 0 for line in text_l: if len(line) > box_width: box_width = len(line) box_width += 4 #print 'box:',box_width top = elements[0]+elements[1]*(box_width-2)+elements[2] bottom = elements[5]+elements[6]*(box_width-2)+elements[7] middle = '' for key,line in enumerate(text_l): #middle += elements[3]+' '+line.ljust(box_width-4)+' '+elements[4] middle += '%s %s %s' % (elements[3], line.ljust(box_width-4), elements[4]) if not key == len(text_l)-1: middle += '\n' #print top #print middle #print bottom nl = '\n' return top+nl+middle+nl+bottom ##def word_wrap(text, chars=79, ignore_codes=True): ## """Inserts linebreaks into a string in order to prevent it wrapping ## in the middle of a word. defaults to the width of the console """ ## ## sentence = [] ## word = '' ## position = 1 ## for letter in text: ## if letter == ' ' or position == len(text): ## word += letter ## sentence.append(word) ## word = '' ## position += 1 ## else:## word += letter ## position +=1 ## ## #code_length = 0 ## charsdisplayed = 0 ## wrapped = '' ## for word in sentence: ## counting = False ## code_length = 0 ## ## #See if there are any codes and remove them from the character count ## #so that word wrapping doesn't get fouled up by character codes. ## if ignore_codes and word.find('~') != -1 and word.find('|') != -1: ## for letter in word: ## if letter == '~': ## counting = True ## elif letter == '|': ## code_length += 1 ## counting = False ## ## if counting: ## code_length += 1 ## word_length = len(word)-code_length ## else: ## word_length = len(word) ## #### print word #### print word_length #### print len(word) #### print code_length #### raw_input() ## ## if charsdisplayed+word_length > chars: ## if not word_length > chars: ## wrapped += '\n'+word ## charsdisplayed = word_length ## else: ## wrapped += word ## lengthdisplayed = word_length + charsdisplayed ## while lengthdisplayed > chars: ## lengthdisplayed -= chars ## charsdisplayed = lengthdisplayed ## else: ## wrapped += word ## if '\n' in word: ## charsdisplayed = word_length - word.find('\n') ## else: ## charsdisplayed += word_length ## ## return wrapped def word_wrap(text,chars=79,ignore_codes=True): if ignore_codes: length = lambda x: len(remove_codes(x)) else: length = lambda x: len(x) lines = text.splitlines() #print lines wrapped='' for line in lines: if length(line) > chars: split_line = line.split() wrapped_line = '' displayed = 0 for word in split_line: if displayed + length(word) > chars: #TODO:split words that are too long for one line here wrapped_line = wrapped_line.strip() wrapped_line += '\n' displayed = 0 wrapped_line += word+' ' displayed += length(word+' ') else: wrapped_line = line if line == ' ': wrapped_line = '\n' wrapped += wrapped_line+'\n' return wrapped def remove_codes(text): """ Remove any colour control codes from a string and return it """ first_code = find_code(text) while first_code != -1: text = text[:first_code] + text[text[first_code:].find('|')+1+first_code:] first_code = find_code(text) return text def find_code(text): code_found = -1 for index,letter in enumerate(text): if letter == '~': if text[index+1].lower() == 'b' or text[index+1].lower() == 'f': if text[index:].find('|') != -1: return index return code_found #Replace this with an implementation of get_tasklist() ? def find_running_process(process): error_exit('find_running_process deprecated, use ProcessRunning instead') """ Uses 'tasklist | find' to find if a process is running. NOTE: It will return True if it finds a process that contains a segment of 'process' string. (i.e. searching for 'explore' will return true because it finds 'explorer' running.""" #these will be 0 if the app IS running. DON'T FORGET. process_running = os.system('tasklist | find /I "'+process+'"') if process_running == 0: process_running_final = True elif process_running == 1: process_running_final = False else: error_exit('find_running_process received an unexpected response from "tasklist | find".\n\nprocess: '+process) return process_running_final def logging(data, log_type=False): """ Dump various Handy Messages and errors out to a logfile. """ if '-nolog' in command_line_switches(): return False if log_type is 'EVENT': if '-eventlog' not in command_line_switches(): return False #sys.path[0] returns the folder of the running script #filename = os.path.join(sys.path[0],'qa_menu.log') #instead we grab filename from a global: filename = log_path ## if os.path.exists(filename) and not os.access(filename,os.W_OK): ## return False try: logfile = codecs.open(filename, 'a', 'utf-8')#out = codecs.open(fname, 'w', 'utf-8') except IOError: print ('Error: Unable to access logfile, user may not have write ' 'permission for "%s"' % filename) print 'Press any key to exit' #wait_for_key() sys.exit() formatted_time = time.strftime('%Y/%m/%d %H:%M:%S') if not log_type: log_type = 'MSG' output_data = formatted_time+' '+str(log_type).upper()+': '+data+'\n' try: logfile.write(output_data) logfile.close() except IOError: error_exit('Logging(): IOError while writing %s' % filename,log=False) reduce_logfile_size(filename) def reduce_logfile_size(logfn='x:\\qa menu\\qa_menu.log',target_size=102400): """delete the beginning of a log file until it is less than a target size""" #if the file doesn't exist, or can't be written to give up #sys.path[0] returns the folder of the running script if not os.path.exists(logfn): logging('Attempted to reduce size of "'+logfn+'", but failed because the file could not be found.') return False #if the file isn't bigger than the target size, give up if not os.stat(logfn).st_size > target_size: return False #See if we don't have write access to the logfile, inform the user if we don't. if not os.access(logfn,os.W_OK): print word_wrap('WARNING: Unable to write to logfile.\n\nThis could mean you don\'t have ' 'admin permission on this PC, or that the logfile is set to \'read only\'') print ('\nPress any key to attempt to continue') wait_for_key() return False #Put the last 'target_size' bytes of data in log_file = open(logfn,'r') try: log_file.seek(-target_size,os.SEEK_END) except IOError: crash_info = (target_size, os.SEEK_END, os.fstat(log_file.fileno())) raise Exception('Weird reduce_logfile_size crash. TELL THOMAS!\n' 'target_size is %s\n' 'os.SEEK_END is %s\n' 'log file fstat:\n%s' % crash_info) log_data = log_file.read() log_file.close() #find the first newline (so that we aren't cutting a line in half) first_newline = log_data.find('\n') last_newline = log_data.rfind('\n') #write the last 'target_size' bytes of data back to the logfile log_file = open(logfn,'w') log_file.write(log_data[first_newline+1:last_newline+1]) log_file.close() #removed logging of this when i decided to reduce logsize every time the #log was added to (because it would create a mad loop of doom) #logging('Reduced "'+logfn+'" to '+str(target_size)+' bytes.') return True def delete_old_pstats(): """ deletes pstats backup folders that are older than a month """ backup_dir = 'x:\\pstats_backup' if not os.path.exists(backup_dir): return False files_and_dirs = os.listdir(backup_dir) one_month = 2629743 #roughly the number of seconds in one month #one_month = 86400*2 #CHANGE THIS, THIS IS ONLY 2 DAYS. one_month_old = time.time() - one_month folders = [] for path in files_and_dirs: full_path = os.path.join(backup_dir,path) if os.path.isdir(full_path): if os.stat(full_path).st_mtime < one_month_old: folders.append(full_path) if len(folders) > 0: logging('Cleaning up "'+backup_dir+'"') for path in folders: logging('Deleting "'+path+'"') shutil.rmtree(path) return True def is_xbox_ready(delay=0.25): """ use xbconsoletype to tell if the default xbox is responding (ie, switched on) Returns False if the xbox doesn't respond within 250ms""" xdk_vars() xbox = subprocess.Popen('xbconsoletype',stdout=subprocess.PIPE, stderr=subprocess.PIPE,universal_newlines=True) start_time = time.time() xbox_responding = False while time.time()-start_time < delay: if xbox.poll() != None: xbox_responding = True break #print time.time()-start_time if xbox_responding: if xbox.communicate()[1].startswith('xbconsoletype: error: cannot ' 'connect to Xbox 360 development ' 'kit'): error_exit('Communications with Xbox failed, please check Xbox 360' ' Neighbourhood and confirm that the target Xbox is ' 'present, and that it has been set as the \'default ' 'xbox \'') return xbox_responding def wait_for_xbox(): #increased delay to 1s to hopefully prevent the 'xbox not responding' #message from appearing too quickly. delay = 1 while not is_xbox_ready(delay): os.system('cls') print box_text('Xbox not responding, please check power and network') time.sleep(delay) KillAllTaskName('xbconsoletype.exe',chatty=False) #=============================================================================== #====Script Managment=========================================================== def compare_script_files(game_id, loop = True): """ compares the scriptfiles described in the game_id and warns the user if their script file doesn't match the one on the network.""" localfile = game_versions[game_id]['script_local'] remotefile = game_versions[game_id]['script_remote'] if not os.path.exists(localfile): error_exit('Cannot find local scriptfile, please check game_versions ' 'profile '+game_id+'\n\nSettings:\n'+localfile+'\n'+remotefile) if not os.path.exists(remotefile): logging('Cannot find remote scriptfile \''+remotefile+'\' for ' 'comparison. GID: '+game_id) do_files_match = False remote_file_found = False else: do_files_match = filecmp.cmp(localfile, remotefile) remote_file_found = True return do_files_match def check_script_warning(game_id): """ Displays a warning if local scripts don't match remote scripts """ if 'script_remote' not in game_versions[game_id] or 'script_local' not in game_versions[game_id]: return False if compare_script_files(game_id) == True: return True else: selection = menu_maker_2('Continue?', ['Yes','No'], 'WARNING: Local scriptfile does not match ' 'reference scriptfile!\n\nIf you are not sure if you should continue, ' 'please select \'No\' and check with someone who looks like they might ' 'know.\n\nScript Checked:' '\n'+os.path.basename(get_setting(game_id, 'script_remote','NO_EXIT'))) if selection == 0: logging(game_id+'failed remote script check. User chose to ignore' ' the error and continue to load the game.') return False elif selection == 1: error_exit('Script file does not match reference file.') def script_manager(game_id): """replace active script with potential scripts from a list of them supplied in game_versions.ini""" active_script = get_setting(game_id,'active_script') scripts = get_setting(game_id,'script_images') script_location = os.path.dirname(active_script) script_files = make_setting_dict(scripts) menu_names = [] script_filenames = [] for clean, filename in script_files.iteritems(): if os.path.exists(os.path.join(script_location,filename)): menu_names.append(clean) script_filenames.append(os.path.join(script_location,filename)) if len(menu_names) == 0: print '\n\nERROR: No non-active script files found in build. \n\nReturning to game page', print_slow_dots(10) return '_BACK' #see if i can work out what the current active script is matching_filepos = [] for position, filename in enumerate(script_filenames): if filecmp.cmp(active_script, filename): matching_filepos.append(position) matching_scripts = '' for position in matching_filepos: matching_scripts += menu_names[position] if matching_scripts != '': comment = 'Current Active Script: '+matching_scripts elif matching_scripts == '': comment = 'Current Active Script: Unable to determine' #comment += '\n\nPlease select a script image to use with '+get_setting(game_id,'name')+'.' selection = menu_maker_2('Script Manager',menu_names,comment) if selection == -1: return '_BACK' if os.path.exists(active_script): os.system('attrib -r '+active_script) os.remove(active_script) shutil.copy2(script_filenames[selection],active_script) logging('Script Manager: Copied "%s" to "%s"' % (script_filenames[selection],active_script)) return menu_names[selection] def make_setting_dict(settings): """ converts a list containing 'filename: cleanname' items into a dictionary""" setting_dict = {} for full_setting in settings: if not ':' in full_setting: error_exit('Malformed setting supplied to make_setting_dict:\n\nFailed on line: '+full_setting) else: split_setting = full_setting.partition(':') setting_dict[split_setting[0]] = split_setting[2].strip() return setting_dict #=============================================================================== #====Tasklist butchering======================================================== def get_tasklist(): error_exit('get_tasklist deprecated, use GetTasklist() instead') def GetTasklist(): """ 'tasklist /v /fo csv' is a much better way of doing this! """ tasklist = subprocess.Popen('tasklist.exe /v /fo csv', stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines = True) tasks_output = tasklist.communicate()[0].strip('\n').split('"\n') # titles from headers headers = [head.strip('"') for head in tasks_output[0].split(',')] tasks = [] for task in tasks_output[1:]: one_task = [item.strip('"') for item in task.split('",')] one_task_dict = {} for key, item in enumerate(one_task): if len(one_task) != 9: error_exit('GetTasklist adanoned ship on task because it ' 'did not have 9 entries: %s' % str(one_task)) one_task_dict[headers[key]] = item tasks.append(one_task_dict) #print len(tasks),tasks[len(tasks)-1]['Image Name'] return tasks def FindTask(proc_name): valid_tasks = [] for task in GetTasklist(): if task['Image Name'].lower() == proc_name.lower(): valid_tasks.append(task) return valid_tasks def FindPID(pid): if not IsPIDRunning(pid): return False valid_tasks = [] for task in GetTasklist(): if task['PID'] == pid: return task #failsafe, if the pid dissapears inbetween checking for it and getting list return False def KillAllTaskName(proc_name,chatty=True): for task in FindTask(proc_name): logging('Killing Task: "%s", PID: %s' %(task['Image Name'], task['PID'])) kill_task(task['PID'],chatty=chatty) def ProcessRunning(proc_name): if len(FindTask(proc_name)) > 0: return True def format_tasklist(line): error_exit('format_tasklist deprecated, use GetTaskList() instead') """ turn a string output by tasklist into a formatted list""" #This works in XP, gotta find out if it works in other windows #versions. if len(line) < 26: return [] tasklist = [None]*6 #process name tasklist[0] = line[0:25].strip() #pid tasklist[1] = line[26:32].strip() if tasklist[1].isdigit(): tasklist[1] = int(tasklist[1]) #memory usage tasklist[2] = line[59:69].strip().replace(',','') if tasklist[2].isdigit(): tasklist[2] = int(tasklist[2]) #status running/not tasklist[3] = line[72:87].strip() #cpu time in seconds time_strings = line[139:151].strip().split(':') time_ints = [] for string in time_strings: time_ints.append(int(string)) tasklist[4] = time_ints[2]+(time_ints[1]*60)+(time_ints[0]*60*60) #window title tasklist[5] = line[152:].strip() return tasklist def is_process_running(processname): error_exit('is_process_running deprecated, use ProcessRunning() instead') matches = 0 for task in get_tasklist(): if task[0].lower() == processname.lower(): matches += 1 if matches > 0: return True else: return False def kill_watson(): error_exit('kill_watson deprecated, use KillAllTaskName instead') running_tasks = get_tasklist() watson_pids = [] for task in running_tasks: if task[0] == 'xbWatson.exe': watson_pids.append(task[1]) for pid in watson_pids: logging('Attempting to kill watson.exe with PID: '+str(pid)) kill_task(pid) def KillRag(): """ Special case for killing rag, to prevent people losing settings """ rag_proc = FindTask('rag.exe') if len(rag_proc) == 0: return True #we should only ever have 1 rag running, so it's easier to do this rag = rag_proc[0] #If rag is only in the systray, we can force kill without problem if rag['Window Title'] == 'N/A': kill_task(rag['PID']) return True #however, if rag has a window title, we need a clean kill kill_task(rag['PID'],force=False) message = 'RAG is refusing to close, it may be asking you to save changes' while IsPIDRunning(rag['PID']): pid = FindPID(rag['PID']) if pid != False: if pid['Window Title'] == 'N/A': break else: break os.system('cls') print box_text(message) time.sleep(1) #keep going until we have no more rags. Shouldn't loop more than twice! if len(FindTask('rag.exe')) > 0: KillRag() def IsPIDRunning(pid): for task in GetTasklist(): if task['PID'] == pid: return True return False def kill_task(pid,force=True, chatty=True): """kills a task by process ID. uses TASKKILL. Tested on: XP""" logging('KILL_TASK: Attempting to gently kill task with PID: '+str(pid)) if chatty: print 'Politely asking %s to close...' % pid, task_killer = subprocess.Popen('taskkill /PID '+str(pid), stdout=subprocess.PIPE, stderr=subprocess.PIPE) if IsPIDRunning(pid): time.sleep(0.8) if IsPIDRunning(pid): if force: if chatty: print '%s has ignored request, forcing kill.' % pid else: if chatty: print '%s has ignored request.' % pid return False else: if chatty: print '%s has closed politely.' % pid while IsPIDRunning(pid): task_killer = subprocess.Popen('taskkill /F /PID '+str(pid), stdout=subprocess.PIPE, stderr=subprocess.PIPE) def kill_taskname(taskname): """ Kills all tasks that match the process name. CAREFUL NOW """ error_exit('kill_taskname deprecated, use KillAllTaskName instead') current_tasks = get_tasklist() pids = [] for task in current_tasks: if task[0].lower() == taskname.lower(): pids.append(task[1]) if len(pids) == 0: logging('KILL_TASKNAME: No instances of '+taskname+' found.') return False for pid in pids: logging('KILL_TASKNAME: Attempting to ' 'kill '+taskname+' with PID: '+str(pid)) kill_task(pid) #====Syncit!==================================================================== def syncit(game_id): """ Run Synchronize It! using a project name located via game_id. Location of synchronize it! is in settings.ini """ #project = 'update_episode1_jap' project = get_setting(game_id,'sync') path = get_setting('defaults','syncit') proj_arg = '/P='+project logfile = 'x:\\sync.html' #kill any instances of rag and systray to prevent synchit failing #KillAllTaskName('rag.exe') KillRag() KillAllTaskName('systrayrfs.exe') #attempt to erase the logfile before creating a new one: if os.path.exists(logfile): os.remove(logfile) sync=subprocess.Popen([path,proj_arg,'/auto','/show-','/log0',logfile]) #print sync.communicate()[0] spinny_thing = ['|','/','-','\\'] spinny_progress = 0 while sync.poll() == None: os.system('cls') print 'Synchronize It! is updating '+project+', please wait'+('.'*spinny_progress) if spinny_progress > len(spinny_thing)-1: spinny_progress = 0 print spinny_thing[spinny_progress] spinny_progress += 1 time.sleep(0.2) sync_message = process_sync_log(logfile) logging('SyncIt: '+project+': '+sync_message) print print 'Last message from Synchronize It! says:' print box_text(sync_message) print print 'Press any key to continue' wait_for_key() print '\nOne moment please...' def process_sync_log(filename='c:\\wndsync-log.html'): """ Read in the Synchronize It! logfile and return the summary of the last operation performed with the /log0 command line used """ if not os.path.exists(filename): return 'Unable to read log' logfile = open(filename,'r') storing = False section = [] for line in logfile: if '' in line: storing = True if storing: section.append(line) if '' in line: break if len(section) < 5: return 'Unable to read log' message_start = section[4].find('')+4 message_end = section[4].find('')-5 message = section[4][message_start:message_end].strip().strip(':') return message #====Japery===================================================================== def windows_username(): """retrieve and format the windows username for japes. Return as a tuple with [0] First [1] Last""" name = os.environ.get('username') if '.' not in name: return [name.capitalize(),'Smith'] namesplit = name.partition('.') firstname = namesplit[0].capitalize() lastname = namesplit[2].capitalize() if name.lower()=='rory.jepson': firstname = 'Rory. You smell of wee' elif name.lower() =='neil.corbett': os.system('color 5d') firstname = 'Lob Erect Tin' elif name.lower() == 'scott.butchard': firstname = 'Bat Crotch Dust' elif name.lower() == 'tarek.hamad': firstname = 'Death Karma' elif name.lower() == 'andrew.scotland': firstname = 'Cat\'s Wonderland' elif name.lower() == 'brian.kelly': firstname = 'Nearby Kill' os.system('color 6e') return [firstname, lastname] def time_of_day(): """ Work out whether it is morning afternoon or night, return a string with an appropriate word in it""" current_hour = int(time.strftime('%H')) #print current_hour if current_hour >= 5 and current_hour <= 11: time_name = 'morning' elif current_hour >= 12 and current_hour <= 17: time_name = 'afternoon' elif current_hour >= 18 and current_hour <= 21: time_name = 'evening' elif current_hour >= 22 or current_hour <= 4: time_name = 'night' return time_name def silly_intro(): """ this isn't a waste of time at all """ intro = ['BBC Computer 32k','Acorn 1770 DFS','BASIC'] command = '> LOAD "QA_MENU"\n\n' for line in intro: for char in line: print char, print print random_wait(0.2) for char in command: print char, random_wait(0.1) print def random_wait(max_wait=1): """ wait for a random time between 0s and max_wait) """ time.sleep(random.uniform(0,max_wait)) def OpenWikiPage(game_id): wikiurl = get_setting('defaults','wikiurl') wikipage = get_setting(game_id,'wikipage') webbrowser.open(wikiurl+wikipage) logging(('Opening wiki page for %s: %s' % (game_id, wikiurl+wikipage))) def ARSEstar(): sequence = ['A.', 'R.', 'S.', 'E.', 'star\n', '!delay=1', '!cls', 'Advanced\nR.\nS.\nE.\nstar', '!cls', 'Advanced\nRockstar\nS.\nE.\nstar', '!cls', 'Advanced\nRockstar\nSelection\nE.\nstar', '!cls', 'Advanced\nRockstar\nSelection\nEngine\nstar',] os.system('cls') for element in sequence: if element == '!delay=1': time.sleep(1) elif element == '!cls': os.system('cls') else: print element time.sleep(0.5) time.sleep(1) def RandomIntro(): if random.randint(1,20) == random.randint(1,100): selection = random.randint(1,2) if selection is 1: silly_intro() elif selection is 2: ARSEstar() #======experiments========================================================================= def move_something(something): original_something = something global object_size object_size = len(something) thing_x = 5 thing_y = 5 ms_screenupdate(something,thing_x,thing_y) while True: key = wait_for_key() if key == 'CURSOR_LEFT': thing_y -= 1 elif key == 'CURSOR_RIGHT': thing_y += 1 elif key == 'CURSOR_UP': thing_x -= 1 elif key == 'CURSOR_DOWN': thing_x += 1 elif key == 'HOME': thing_x =11 thing_y = 35 something = original_something object_size = len(something) elif key == 'INSERT': something = 'tarek is a boner' object_size = len(something) elif key == 'PAGE_DOWN': something = 'tarek is a stunted boner' object_size = len(something) else: if something == original_something: something = key else: something += key object_size = len(something) thing_x,thing_y = ms_force_constraints(thing_x,thing_y) ms_screenupdate(something,thing_x,thing_y) def ms_force_constraints(x,y): if x > 23: x=23 elif x < 1: x=1 if y > 79-object_size: y=79-object_size+1 if y < 0: y=0 if x == 23 and y == 79-object_size+1: y=78-object_size+1 return x,y def ms_screenupdate(thing,pos_x,pos_y): os.system('cls') debugstring = 'x: '+str(pos_x)+' y: '+str(pos_y) string = debugstring+('\n'*pos_x)+(' '*pos_y)+thing print string def fun_with_stats(filename='thing.pstats'): statsfile = open(filename,'r') outfile = open('outfile.pstats','w') whole_thing = '' for line in statsfile: whole_thing += line all_items = split_pstats(whole_thing) vehicles_used = pstats_vehicles_used(all_items,'VEHICLE_ENTERED') vehicles_left = pstats_vehicles_used(all_items,'VEHICLE_LEFT') print '------------------------------------------' print '| Vehicle | Times in | Times out |' print '|==============|============|============|' for vehicle in sorted(vehicles_used.iterkeys()): times_used = vehicles_used[vehicle] if vehicle in vehicles_left: times_left = vehicles_left[vehicle] else: times_left = 0 times_left_spaces = ' '*(12-len(str(times_left))) vehicle_spaces = ' '*(14-len(vehicle)) times_used_spaces = ' '*(12-len(str(times_used))) print '|' + vehicle + vehicle_spaces + '|' + str(times_used) + times_used_spaces + '|' + str(times_left) + times_left_spaces + '|' print '------------------------------------------' ## for one_object in all_items: ## for key, value in one_object.iteritems(): ## print key,'=',value ## print '---------------' #for item in all_items: # outfile.write(item+'\n') #outfile.close() def pstats_prettify(filename='thing.pstats'): in_file = open(filename,'r') #out_file = open('pretty.pstats','w') out_name = os.path.join(os.path.dirname(filename), 'pretty_'+os.path.basename(filename)) out_file = open(out_name,'w') stats_data = '' for line in in_file: stats_data += line pstats = split_pstats(stats_data) for event in pstats: for statname, stat in event.iteritems(): out_file.write(str(statname)+' = '+str(stat)+'\n') out_file.write('-----------------\n') out_file.close() def pstats_vehicles_used(pstats,psid): start_time=time.time() vehicles = {} for event in pstats: if 'psid' in event: if event['psid'] == psid: if event['name'] not in vehicles: vehicles[event['name']] = 1 else: vehicles[event['name']] += 1 end_time = time.time() print 'vehicle processing completed in', print end_time-start_time return vehicles def split_pstats(line): start = time.clock() one_id = re.compile('[gp]sid=.*?(?=$|[gp]sid)') split_id = re.compile('[^|,].*?=.*?(?=$|,)') final = [] for sid in one_id.findall(line): full_split = {} for data_split in split_id.findall(sid): one_split = data_split.split('=') full_split[one_split[0]] = one_split[1] final.append(full_split) end = time.clock() print 'pstats processing completed in %ss' % (end-start) return final ##old way, without using regex ##def split_pstats(line): ## all_split = [] ## one_thing = '' ## total = len(line) ## starttime = time.time() ## for pos, char in enumerate(line): ## one_thing += char ## #print pos,'out of',total ## if pos == total-1: ## #print 'end hit' ## break ## if line[pos+1] == 'g' or line[pos+1] == 'p': ## if line[pos+2:pos+5] == 'sid': ## all_split.append(one_thing) ## one_thing = '' ## ## all_split.append(one_thing) ## ## pstats = [] ## for one_object in all_split: ## one_object_split = one_object.split(',') ## one_object_dict = {} ## for key_value in one_object_split: ## key_value_split = key_value.split('=') ## one_object_dict[key_value_split[0]] = key_value_split[1].strip('"') ## pstats.append(one_object_dict) ## ## ## ## endtime = time.time() ## total_time = endtime-starttime ## print 'pstats processing completed in', ## print total_time ## return pstats def pstats_track_path(filename='thing.pstats'): stats_file = open(filename,'r') stats_data_line = '' for line in stats_file: stats_data_line += line pstats = split_pstats(stats_data_line) player_path = [] for single_event in pstats: if 'psid' in single_event: #if single_event['psid'] == 'COORDS': if single_event['psid'] == 'SPAWN': player_path.append(['','']) if 'x' in single_event and 'y' in single_event: player_path.append([single_event['x'],single_event['y']]) path_file = open('path.csv','w') for key,position in enumerate(player_path): path_file.write(position[0]+', '+position[1]+'\n') path_file.close() def distance_between(x1,y1,x2,y2): import math final_dist = math.sqrt(pow(x2-x1,2)+pow(y2-y1,2)) return final_dist ##this is a terrible way of doing it, leave it here to remind you of AWFULNESS ##def split_oddly(line): ## sid_pos = 0 ## end_pos = 5 ## lines = [] ## tempfile = open('temp.pstats','w') ## time1 = time.time() ## ## while sid_pos != -1: ## sid_pos = line.find('sid=',end_pos) ## #print sid_pos ## ## if line[sid_pos-2] != ',': ## new_line = '\n'+line[end_pos-5:line.find('sid=',sid_pos)-1] ## tempfile.write(new_line) ## ## end_pos = sid_pos+4 ## print end_pos, len(line) ## print str(int((float(end_pos) / (len(line)))*100))+'%' ## #print percentage,'%' ## time2 = time.time() ## print 'time diff='+str(time2-time1) ## tempfile.close() ## return line #=============================================================================== def sp_or_mp(game_id): """use 'logdestination' to work out if the user was playing multiplayer or singleplayer, return false if it can't work it out""" if 'singleplayer' in get_setting(game_id,'logdestination').lower(): gametype = 'singleplayer' elif 'multiplayer' in get_setting(game_id,'logdestination').lower(): gametype = 'multiplayer' else: gametype = False return gametype def client_or_host(game_id): """use console logs to work out if the player was a client or host, return false if it can't work it out.""" games_hosted = 0 games_joined = 0 host_text = 'Hosting STANDARD session' client_text = 'Setting session id (from host)' #print valid_console_logs(game_id) for filename in valid_console_logs(game_id): #print '[%s]' % filename console_log = open(filename) for line in console_log: if host_text in line: games_hosted += 1 #print line elif client_text in line: games_joined += 1 #print line #if it looks like a game has been hosted AND joined, return false if games_hosted > 0 and games_joined > 0: playertype = False #if it looks like a game has neither been hosted nor joined, return false elif games_hosted == 0 and games_joined == 0: playertype = False #looks like a host elif games_hosted > 0 and games_joined == 0: playertype = 'host' #looks like a client elif games_hosted == 0 and games_joined > 0: playertype = 'client' return playertype def upload_logs2(game_id): """stuff""" gametype = sp_or_mp(game_id) while True: playertype = client_or_host def valid_console_logs(game_id): """return the filenames of all valid console logs in the logging directories described for the game_id in game_versions""" files_with_console = [] for location in get_setting(game_id,'logsource'): files_with_console += directory_list(location,'console') #print files_with_console if len(files_with_console) > 0: files_with_console_and_log = [] for filename in files_with_console: if filename.endswith('log'): files_with_console_and_log.append(filename) elif len(files_with_console) < 1: files_with_console_and_log = [] return files_with_console_and_log #====crap======================================================================= def temp_mp_backup(multiplayer): pass ##def copy_files(sources, destinations): ## """ copy files from sources to destinations """ ## ## #if the number of sources don't match the number of destinations, abandon ship ## if len(sources) != len(destinations): ## error_exit('The number of sources supplied to copy_files() did not match the number of destinations') ## ## blocksize = 1024 #1k block size, copy a kilobyte at a time then refresh screen ## ## total_files = len(sources) ## ## overall_percentage = 0 ## file_percentage = 0 ## ## #get overall filesize ## total_size = 0 ## for filename in sources: ## if not os.path.exists(filename): ## error_exit('Trying to copy a file that doesn\'t exist: "'+filename+'"') ## total_size += os.stat(filename).st_size ## ## for index, filename in enumerate(sources): ## if os.path.exists(destinations[index]): ## error_exit('Trying to copy a file to a location that already exists: "'+destinations[index]+'"') ## ## if not os.path.exists(os.path.dirname(destinations[index])): ## error_exit('Trying to copy a file to a folder that does not exist: "'+destinations[index]+'"') ## ## if not os.access(filename,os.R_OK): ## error_exit('"'+filename+'"'+' could not be read.') ## ## in_file = open(filename,'r') ## out_file = open(destinations[index],'a') ## ## total_bytes def print_progress_bar(title, current_source, current_destination, file_percentage, overall_percentage): """ display a progress bar with all those STATS """ os.system('cls') if file_percentage > 100 or overall_percentage > 100: error_exit('print_progress_bar(): percentages should not be greater than 100') surround = '-' end = '|' block = '*' spacer = ' ' bar_length = 50 file_blocks = int(round(bar_length*file_percentage/100)) print surround*(bar_length+2) print end+block*file_blocks+spacer*(bar_length-file_blocks)+end print surround*(bar_length+2) #====WConio experiments========================================================= def printc(text,xy=[-1,-1],max_xy=[79,24]): #print xy if xy == [-1,-1]: xy = [WConio.wherex(),WConio.wherey()] start_x = xy[0] text = word_wrap(text, max_xy[0]-start_x) display = True for index, char in enumerate(text): #See if the character is special text character (~) if text[index-1] == '|' and not display: display = True if char == '~': fore_or_back = '' display = False #look at the next character to see if it's F or B if text[index+1].lower() == 'f': fore_or_back = 'f' display = False elif text[index+1].lower() == 'b': fore_or_back = 'b' display = False #if it's probably a colour code, get the colour from it if fore_or_back: colour_char = '' colour_word = '' colour_index = 2 while not text[index+colour_index] == '|': colour_char = text[index+colour_index] colour_word += colour_char colour_index += 1 if fore_or_back == 'f': if colour_word: text_colour(colour_word) else: text_colour() fore_or_back = '' elif fore_or_back == 'b': if colour_word: bg_colour(colour_word) else: bg_colour() fore_or_back = '' if display: if char == '\n': xy[1] += 1 xy[0] = start_x else: gotoxy(xy) WConio.putch(char) if xy[0]+1 > max_xy[0]: xy[1] += 1 if xy[1] > max_xy[1]: return xy[0] = start_x else: xy[0] += 1 def gotoxy(xy,max_xy=[79,300],min_xy=[0,0]): """ Use WConio to position the cursor in x y, don't go out of constraints """ if xy[0] > max_xy[0] or xy[0] < min_xy[0]: WConio.gotoxy(0,0) text_colour('Black') bg_colour('red') print 'ERROR: Text cursor placed outside of constraints', xy text_colour() bg_colour() xy = [0,1] if xy[1] > max_xy[1] or xy[1] < min_xy[1]: WConio.gotoxy(0,0) text_colour('Black') bg_colour('red') print 'ERROR: Text cursor placed outside of constraints', xy text_colour() bg_colour() xy = [0,1] WConio.gotoxy(xy[0],xy[1]) def text_colour(colour='green'): WConio.textcolor(colours(colour)) def bg_colour(colour='black'): WConio.textbackground(colours(colour)) def colours(colour): """ Convert numbers or words into WConio compatible colours """ if str(colour).isdigit(): if int(colour) >= 0 and int(colour) <= 15: final_colour = int(colour) else: final_colour = WConio.LIGHTGRAY else: if colour.lower() == 'black': final_colour = WConio.BLACK elif colour.lower() == 'blue': final_colour = WConio.LIGHTBLUE elif colour.lower() == 'green': final_colour = WConio.LIGHTGREEN elif colour.lower() == 'red': final_colour = WConio.LIGHTRED elif colour.lower() == 'cyan': final_colour = WConio.LIGHTCYAN elif colour.lower() == 'magenta': final_colour = WConio.LIGHTMAGENTA elif colour.lower() == 'dblue': final_colour = WConio.BLUE elif colour.lower() == 'dgreen': final_colour = WConio.GREEN elif colour.lower() == 'dcyan': final_colour = WConio.CYAN elif colour.lower() == 'dred': final_colour = WConio.RED elif colour.lower() == 'dmagenta': final_colour = WConio.MAGENTA elif colour.lower() == 'brown': final_colour = WConio.BROWN elif colour.lower() == 'grey': final_colour = WConio.LIGHTGREY elif colour.lower() == 'dgrey': final_colour = WConio.DARKGREY elif colour.lower() == 'yellow': final_colour = WConio.YELLOW elif colour.lower() == 'white': final_colour = WConio.WHITE else: final_colour = WConio.LIGHTGREY return final_colour def cls(home=False): cursor_position = [WConio.wherex(),WConio.wherey()] WConio.clrscr() if not home: gotoxy(cursor_position) def invert_colours(): colours = current_colours() text_colour(colours[1]) bg_colour(colours[0]) def current_colours(): #I should probably learn how to 'do' bitwise stuff. colours = WConio.gettextinfo()[4] bg = colours >> 4 fg = colours - (bg << 4) return [fg,bg] #=============================================================================== #old rdr commandlines backup - new one should only modify the ones we need to, #gather the rest from commandlines.txt ##def rdr_commandlines(game_id,path='x:\\rdr2\\rdr_cmd.txt'): ## """ create a text file containing all the commandlines found in an rdr ## game_id """ ## ## if path[-4:].lower() != '.txt': ## error_exit('Panicky Pete Alert: The path supplied to rdr_commandlines ' ## 'is not a *.txt file: '+path) ## ## if os.path.exists(path) and not os.access(path,os.W_OK): ## error_exit('WARNING: Unable to write to '+path+'\n\nThis could mean ' ## 'you don\'t have admin permission on this PC, or that the ' ## 'file is set to \'read only\'') ## ## switches = get_setting(game_id,'switches') ## ## cmdfile = open(path,'w') ## ## for switch in switches: ## cmdfile.write(switch+' ') ## ## cmdfile.close() ## ## print len(switches),'command line switches written to',path def rdr_commandlines(game_id, path, commandline): """ create a text file containing all the commandlines found in an rdr game_id """ if path[-4:].lower() != '.txt': error_exit('Panicky Pete Alert: The path supplied to rdr_commandlines ' 'is not a *.txt file: '+path) if os.path.exists(path) and not os.access(path,os.W_OK): error_exit('WARNING: Unable to write to '+path+'\n\nThis could mean ' 'you don\'t have admin permission on this PC, or that the ' 'file is set to \'read only\'') if not os.path.exists(commandline): error_exit('WARNING: Unable to find RDR commandlines at '+commandline) custom_switches = get_setting(game_id,'switches') cmdline = open(commandline,'r') switches = [] for line in cmdline: switches.append(line) cmdline.close() #check for -megarpf, remove -path from switches+custom_switches remove_path = False for switch in switches: if switch.lower().startswith('-megarpfs'): remove_path = True for switch in custom_switches: if switch.lower().startswith('-megarpfs'): remove_path = True if remove_path: print 'rdr_commandline: -megarpfs found, removing -path' new_switches = [] for switch in switches: if not switch.lower().startswith('-path'): new_switches.append(switch) switches = new_switches new_custom_switches = [] for switch in custom_switches: if not switch.lower().startswith('-path'): new_custom_switches.append(switch) custom_switches = new_custom_switches #check for -rag, remove -localconsole remove_lconsole = False for switch in switches: if switch.lower().startswith('-rag'): remove_lconsole = True for switch in custom_switches: if switch.lower().startswith('-rag'): remove_lconsole = True if remove_lconsole: print 'rdr_commandline: -rag found, removing -localconsole' new_switches = [] for switch in switches: if not switch.lower().startswith('-localconsole'): new_switches.append(switch) switches = new_switches new_custom_switches = [] for switch in custom_switches: if not switch.lower().startswith('-localconsole'): new_custom_switches.append(switch) custom_switches = new_custom_switches #new switch or modified switch? switches_applied = [] for key, switch in enumerate(switches): for custom_key, custom_switch in enumerate(custom_switches): if switch.startswith(custom_switch.split('=')[0]): switches[key] = custom_switch+'\n' switches_applied.append(custom_key) if custom_switch in switch: switches_applied.append(custom_key) cmdfile = open(path,'w') switches_out = 0 for switch in switches: cmdfile.write(switch.strip('\n')+'\n') switches_out += 1 for key, switch in enumerate(custom_switches): if key not in switches_applied: cmdfile.write(switch+'\n') switches_out += 1 cmdfile.close() print switches_out,'command line switches written to',path def quicky(path='X:\\rdr2\\build\\commandline.txt'): outfile = open('commands.txt','w') infile = open(path,'r') for line in infile: outfile.write(line.strip('\n')+', ') outfile.close() infile.close() def profile_latest_saves(drive=0,game='GTA4'): """ Produce a list of paths to profiles that contain valid saves on the selected drive. 0: HDD, 1: Memory Unit 1, 2: Memory Unit 2 """ xbox_drives = ['HDD','MU0','MU1'] gamehex = '545407f2' savepath = os.path.join(gamehex,'00000001') #cheat this until i can be bothered to make an interface selected_drive = xbox_drives[drive] start_folder = selected_drive+':\\'+'Content'#os.path.join(selected_drive,'Content') #get a list of all the profiles inside the content folder of the selected #drive content_folder = [] for folder in xbdir_list(start_folder,True): content_folder.append(os.path.join(start_folder,folder[0])) #Get a list of profile locations with the game hex we're looking for valid_profiles = [] for folder in content_folder: folder_contents = xbdir_list(folder,True) for subfolder in folder_contents: if subfolder[0].lower() == gamehex.lower(): valid_profiles.append(folder) #Get the newest modified on date from the save files. 0 means no saves! profiles_and_dates = [] for index,profile in enumerate(valid_profiles): newest_date=0 savename = '' for saves in xbdir_list(os.path.join(profile,savepath)): if saves[2] > newest_date: newest_date = saves[2] savename = saves[0] profiles_and_dates.append([profile,newest_date,savename]) #remove any profiles with no saves final_profiles = [] for profile in profiles_and_dates: if profile[1] == 0: pass else: final_profiles.append(profile) return final_profiles def archive_profile(xbpath): temp = 'x:\\temp_profile' if os.path.exists(temp): os.remove(temp) def pstats_timeline(statfile='thing.pstats'): outfile = open('timeline.txt','w') infile = open(statfile,'r') stats = split_pstats(infile.read()) previous_time = 0 for full_stat in stats: if full_stat['time'] != previous_time: outfile.write('\n\n'+full_stat['time']+'\n====\n') previous_time = full_stat['time'] for statname, stat in full_stat.iteritems(): outfile.write(str(statname)+' = '+str(stat)+'\n') outfile.write('-----------------\n') outfile.close() infile.close() #======object oriented what's that============================================== class MenuMaker: """ makes menus """ def __init__(self, heading, items): self.heading = heading self.items = list(items) self.comments = False self.default_comment = False self.selection = 0 self.NO_BACK = False self.NO_SORT = True self.show_numbers = False self.lselect = '-->' self.rselect = '<--' self.spacer = ' '*len(self.lselect) self.back_text = 'Back' self.max_item_length = 71 self.menu_position = 0 self.valid_keys = ['CURSOR_UP', 'CURSOR_DOWN', 'ESCAPE', 'RETURN', 'BACKSPACE', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'N', 'O', 'V', 'F10', 'G',] self.menu_stack = [] self.AddEvent(['update_screen',self.menu_position]) self.RefreshActiveItems() def AddEvent(self,event,delay=0): event = Event(event[0], event[1], self.menu_position, self.selection, delay) self.menu_stack.append(event) def ListItems(self): new_items = copy.deepcopy(self.items) if self.NO_SORT: pass elif not self.NO_SORT: new_items.sort() if self.NO_BACK: pass elif not self.NO_BACK: new_items.append([self.back_text,'go_back','back']) if self.show_numbers: for index,item in enumerate(new_items): new_items[index][0] = str(index+1)+'. '+item[0] for index,item in enumerate(new_items): if len(item[0]) > self.max_item_length: new_items[index][0] = item[0][0:self.max_item_length] return self.FillComments(new_items) def SortItems(self): self.NO_SORT = False self.RefreshActiveItems() def RemoveBack(self): self.NO_BACK = True self.RefreshActiveItems() def ChangeBackText(self,new_text): self.back_text = new_text self.RefreshActiveItems() def RefreshActiveItems(self): self.active_items = self.ListItems() def DisableKey(self,key): to_delete = [] for index, valid_key in enumerate(self.valid_keys): if key == valid_key: to_delete.append(index) if len(to_delete) > 0: for index in to_delete: del self.valid_keys[index] def ToggleDisplayNumbers(self): if self.show_numbers: self.show_numbers = False elif not self.show_numbers: self.show_numbers = True self.RefreshActiveItems() self.AddEvent(['update_screen',self.menu_position]) def UpdateScreen(self): #do a print before the cls because if you don't, the last print could #have ended with a comma, which adds a single space after doing a cls print os.system('cls') print box_text(self.heading,1) #print menu items (including selector) for index,item in enumerate(self.active_items): if self.selection == index: lspacer = self.lselect rspacer = self.rselect else: lspacer = self.spacer rspacer = self.spacer if not self.NO_BACK and index == len(self.active_items)-1: print print lspacer,item[0],rspacer print print box_text(self.active_items[self.selection][3]) def FillComments(self,items): for index, item in enumerate(items): if len(item) == 3: if item[1] == 'go_back': if item[0].lower() == 'quit': comment = 'No, don\'t go!' else: comment = 'Previous menu' else: comment = 'Bustin makes me feel good' items[index].append(comment) return items def CursorUp(self): if self.selection == 0: self.selection = self.HighestSelection() else: self.selection -= 1 self.AddEvent(['update_screen',self.menu_position]) def CursorDown(self): if self.selection == self.HighestSelection(): self.selection = 0 else: self.selection += 1 self.AddEvent(['on_select',[self.active_items[self.selection][1], self.active_items[self.selection][2]]]) self.AddEvent(['update_screen',self.menu_position]) def HighestSelection(self): return len(self.active_items)-1 def ReturnEvent(self): self.AddEvent([self.active_items[self.selection][1], self.active_items[self.selection][2]]) def NumkeySelect(self,key): button_select = int(key)-1 if button_select+1 == 0: return False if button_select > len(self.active_items)-1: return False else: self.selection = button_select self.AddEvent(['update_screen',self.menu_position]) self.ReturnEvent() return True def ProcessKey(self,key): numkeys = [] for num in range(0,10): numkeys.append(str(num)) #print 'down:',key if key.upper() not in self.valid_keys: return if key == 'CURSOR_UP': self.CursorUp() elif key == 'CURSOR_DOWN': self.CursorDown() elif key == 'RETURN': self.ReturnEvent() elif key.upper() == 'N': self.ToggleDisplayNumbers() elif key.upper() == 'G': print '['+self.active_items[self.selection][1]+']', print '['+self.active_items[self.selection][2]+']' elif key.upper() == 'ESCAPE': self.AddEvent(['exit_query',self.menu_position]) elif key.upper() == 'O': self.AddEvent(['choose_date','place_order']) elif key.upper() == 'V': self.AddEvent(['choose_date', 'view_orders']) elif key in numkeys: self.NumkeySelect(key) class MenuHandler: def __init__(self): self.events = [] self.menu = [] self.currentmenu = 0 self.last_process = time.clock() self.last_key_read = time.clock() self.key_history = [] time.clock() self.final_event = None def GatherMenuEvents(self): for index,menu in enumerate(reversed(self.menu)): while len(menu.menu_stack) is not 0: event = menu.menu_stack.pop(0) self.events.append(event) def CatMenuItems(self): categories = get_categories() cat_items = [] for cat in categories: cat_items.append([cat, 'select_category', cat, ('Good %s, %s. Would you like to play %s today?' % (time_of_day(),windows_username()[0],cat))]) return cat_items def CategoryContents(self,category): categories = [] for game_id in game_versions.ListGIDs(): if get_setting(game_id, 'category').lower() == category.lower(): categories.append([get_setting(game_id,'name'), 'select_game_page', game_id, 'Let\'s play %s' % get_setting(game_id,'name')]) return categories def CategoryMenu(self,category): self.AddMenu(MenuMaker(category,self.CategoryContents(category))) self.menu[self.currentmenu].SortItems() def TopMenu(self): """ Erase all current menus and snap back to the top category menu. Essentially resets the menu system to a safe point. """ self.menu = [] self.AddMenu(GamesMenu()) self.menu[self.currentmenu].ChangeBackText('Quit') def UpdateScreen(self): """ Print the contents of the currently selected menu to the screen """ self.menu[self.currentmenu].UpdateScreen() def AddKeyEvents(self): self.last_key_read = time.clock() key = get_keypress() if key is not False: self.AddEvent(['key_pressed',key]) self.UpdateKeyHistory(key) self.CheckCodes() #logging('added key event','DEBUG') key = get_keypress() def ProcessKeyEvent(self,event): if event.EventType() is not 'key_pressed': error_exit('Somehow a non-key_pressed event got sent to the ' 'key event processor. Shouldn\'t happen!') if event.Data() == 'BACKSPACE': self.AddEvent(['go_back',self.currentmenu]) elif event.Data() == 'F10': self.AddEvent(['top_menu',self.currentmenu]) elif event.Data() == 'F12': #self.AddEvent(['final_event','test-me-do']) print 'Opening QA drive...' subprocess.Popen('explorer \\\\rsgedisan1n1\\qa$') elif event.Data() == 'F11': print __name__ else: #todo: send key events to potentially not the active menu? self.menu[self.currentmenu].ProcessKey(event.Data()) def AddMenu(self,menu): self.menu.append(menu) self.currentmenu = len(self.menu)-1 self.menu[self.currentmenu].menu_position = self.currentmenu def RemoveTopMenu(self): self.menu.pop(self.currentmenu) self.currentmenu = len(self.menu)-1 def AddEvent(self,event,delay=0): """ Add an event to the stack """ event = Event(event[0], event[1], self.currentmenu, self.menu[self.currentmenu].selection, delay) self.events.append(event) def ProcessEvent(self): """Read from the event stack. If there's nothing in the event stack, check the key buffer """ clear_buffer_timeout = 5 #clear the key buffer if we haven't had access to it for 5 seconds if time.clock() - self.last_process > clear_buffer_timeout: clear_key_buffer() self.last_process = time.clock() undelayed_events = 0 for event_delays in list(self.events): if event_delays.Delay() is 0: undelayed_events += 1 if undelayed_events == 0: self.GatherMenuEvents() if undelayed_events == 0: self.AddKeyEvents() if undelayed_events == 0: time.sleep(0.001) return event = self.events.pop(0) if event.Delay() is not 0: self.events.append(event) #logging(str(EventLogging(event))+' delayed for '+str(event.Delay()),'DELAY') return logging(str(EventLogging(event)),'EVENT') #event:key_pressed if event.EventType() == 'key_pressed': self.ProcessKeyEvent(event) #event:on_select elif event.EventType() == 'on_select': self.OnSelectEvents(event) #event:select_category elif event.EventType() == 'select_category': self.CategoryMenu(event.Data()) #event:select_game elif event.EventType() == 'select_game': self.AddMenu(OneGameMenu(event.Data())) #event:select_game_page elif event.EventType() == 'select_game_page': self.GamePage(event.Data()) #event:update_screen elif event.EventType() == 'update_screen': self.UpdateScreen() #event:lan_toggle_dlc elif event.EventType() == 'lan_toggle_dlc': toggle_id = event.Data()[0] toggle_dlc = event.Data()[1] if toggle_dlc in game_versions[toggle_id]['lan_dlc_disabled']: game_versions[toggle_id]['lan_dlc_disabled'].pop( game_versions[toggle_id]['lan_dlc_disabled'].index( toggle_dlc)) else: game_versions[toggle_id]['lan_dlc_disabled'].append(toggle_dlc) self.RemoveTopMenu() self.AddMenu(LANDLCMenu(toggle_id)) #event:disable_switches_menu elif event.EventType() == 'disable_switches_menu': self.AddMenu(GetSwitchesMenu(game_versions[event.Data()], False)) #event:enable_switches_menu elif event.EventType() == 'enable_switches_menu': self.AddMenu(GetSwitchesMenu(game_versions[event.Data()], True)) #event:manage_switches elif event.EventType() == 'manage_switches': items = [] if len(game_versions[event.Data()]['switches']) != 0: items.append(['Disable Switch', 'disable_switches_menu', event.Data(), 'Temporarily disable a switch']) if 'disabled_switches' in game_versions[event.Data()]: if len(game_versions[event.Data()]['disabled_switches']) != 0: items.append(['Enable Switch', 'enable_switches_menu', event.Data(), 'Enable a previously disabled switch']) self.AddMenu(MenuMaker('Manage Switches', items)) #event:disable_switch elif event.EventType() == 'disable_switch': gid = game_versions[event.Data()[0]] if 'disabled_switches' not in gid: gid['disabled_switches'] = [] new_switches = [] for idx, switch in enumerate(gid['switches']): if idx == event.Data()[1]: gid['disabled_switches'].append(switch) continue else: new_switches.append(switch) gid['switches'] = ', '.join(new_switches) print ', '.join(new_switches) self.AddEvent(['go_back',0]) self.AddEvent(['go_back',0]) elif event.EventType() == 'enable_switch': gid = game_versions[event.Data()[0]] add_switch = gid['disabled_switches'].pop(event.Data()[1]) switches = copy.copy(gid['switches']) switches.append(add_switch) gid['switches'] = ', '.join(switches) self.AddEvent(['go_back', 0]) self.AddEvent(['go_back',0]) #event:go_back elif event.EventType() == 'go_back': if self.menu[self.currentmenu].NO_BACK == True: pass else: if self.currentmenu == 0: self.final_event = '_BACK' self.AddEvent(['exit_query',0]) else: del self.menu[self.currentmenu] self.currentmenu -= 1 self.AddEvent(['update_screen',self.currentmenu]) #event:exit elif event.EventType() == 'exit': print 'exiting', print_slow_dots() sys.exit() #event:exit_query elif event.EventType() == 'exit_query': items = [['Yes', 'exit', self.currentmenu, 'Exit the QA Menu']] self.AddMenu(MenuMaker('Quit?',items)) self.menu[self.currentmenu].ChangeBackText('No') self.menu[self.currentmenu].DisableKey('ESCAPE') #event:update_loop elif event.EventType() == 'update_loop': self.AddEvent(['check_for_update',0]) self.AddEvent(['update_loop',event.Data()],delay=event.Data()) #event:xex elif event.EventType() == 'xex': launch_gta_iv(event.Data()) self.AddEvent(['update_screen',self.currentmenu]) #event:self elif event.EventType() == 'self': launch_ps3(event.Data()) self.AddEvent(['update_screen',self.currentmenu]) #event:set_home elif event.EventType() == 'set_home': SetPS3Home(event.Data()) self.AddEvent(['update_screen',self.currentmenu]) #event:lan_select_dlc elif event.EventType() == 'lan_select_dlc': self.AddMenu(LANDLCMenu(event.Data())) #event:jimmy_level elif event.EventType() == 'jimmy_level': self.AddMenu(JimmyLevelSelect(event.Data())) #event:identify_version elif event.EventType() == 'identify_version': IdentifyVersionScreen(game_versions[event.Data()]) self.AddEvent(['update_screen',self.currentmenu]) #event:self_custom_switch elif event.EventType() == 'self_custom_switch': launch_ps3(event.Data()[0],event.Data()[1]) self.AddEvent(['update_screen',self.currentmenu]) #event:xex_custom_switch elif event.EventType() == 'xex_custom_switch': launch_gta_iv(event.Data()[0],event.Data()[1]) self.AddEvent(['update_screen',self.currentmenu]) #event:upload_logs elif event.EventType() == 'upload_logs': upload_logs(event.Data()) self.AddEvent(['update_screen',self.currentmenu]) #event:open_log_folder elif event.EventType() == 'open_log_folder': os.startfile(get_setting(event.Data(),'logdestination')) #event:script_manager elif event.EventType() == 'script_manager': active_script = script_manager(event.Data()) if active_script != '_BACK': active_script = 'Active script changed to \'%s\'.' % active_script self.ChangeComment(event,active_script) self.AddEvent(['update_screen',self.currentmenu]) #event:cab_transfer elif event.EventType() == 'cab_transfer': cab_transfer(event.Data()) self.menu[event.SourceMenu()].RefreshActiveItems() self.AddEvent(['update_screen',self.currentmenu]) #event:check_cab_file elif event.EventType() == 'check_cab_file': cabs_match = using_latest_cab_file(event.Data()) if cabs_match: self.ChangeComment(event, ('Check passed! Check performed at %s. ' 'The CAB file on your 360 matches the cab ' 'file on your PC.' % time.strftime('%H:%M:%S'))) elif not cabs_match: self.ChangeComment(event, ('Check Failed! Check performed at %s. ' 'The cab file on your 360 does not match the ' 'cabfile on your PC. Try using Transfer CAB ' 'again.' % time.strftime('%H:%M:%S'))) #event:pkg elif event.EventType() == 'pkg': os.system('cls') PS3InstallPKG(game_versions[event.Data()]) self.AddEvent(['update_screen',self.currentmenu]) #event:script_report elif event.EventType() == 'script_report': self.ChangeComment(event, ScriptReport(game_versions[event.Data()] ['script_report'])) #event:prepare_for_emulation elif event.EventType() == 'prepare_for_emulation': prepare_for_emulation(event.Data()) self.AddEvent(['update_screen',event.Data()]) #event:syncit elif event.EventType() == 'syncit': syncit(event.Data()) self.AddEvent(['go_back',self.currentmenu]) self.AddEvent(['select_game_page',event.Data()]) self.AddEvent(['update_screen',event.Data()]) #event:sleep elif event.EventType() == 'sleep': time.sleep(event.Data()) #event:toggle_numbers elif event.EventType() == 'toggle_numbers': self.menu[event[1]].ToggleDisplayNumbers() self.AddEvent(['update_screen',event.Data()]) #event:check_for_update elif event.EventType() == 'check_for_update': print 'Checking menu version...', check_menu_update() print 'no update required.' print 'Checking for Syncit profile update...', if update_sync_ini(): print 'Sync ini updated' else: print 'no update required' self.AddEvent(['update_screen',event.Data()],10) #event:top_menu elif event.EventType() == 'top_menu': self.TopMenu() #event:wiki_page elif event.EventType() == 'wiki_page': OpenWikiPage(event.Data()) #event:set_socket_port elif event.EventType() == 'set_socket_port': SetSocketPort(event.Data()) comment = ('Temporarily change the socketport. Socketport ' 'currently set to: %s' % CurrentSocketPort(event.Data())) self.ChangeComment(event,comment) #event:begin_emu elif event.EventType() == 'begin_emu': print 'erasing logs...' delete_logs(event.Data()) print 'loading emulator...' emu = XBDiscEmulator() emu.StartEmulator() print 'setting log file...' emu.SetLogFile(os.path.join(os.environ.get('RAGE_CRASHDUMP_DIR'), LogFilename())) print 'loading layout...' emu.LoadMedia(game_versions[event.Data()]['xgd']) print 'starting emulation...' emu.StartEmulation() self.AddEvent(['update_screen',self.currentmenu]) #event:begin_debug_emu elif event.EventType() == 'begin_debug_emu': print 'erasing logs for %s...' % event.Data() delete_logs(event.Data()) #TODO: add a thing here to run systrayrfs without running rag run_watson(event.Data()) DoLaunchPreparations(event.Data()) print 'loading emulator...' emu = XBDiscEmulator() emu.StartEmulator() print 'setting log file...' crashdump_dir = os.environ.get('RAGE_CRASHDUMP_DIR') if crashdump_dir == None: crashdump_dir = os.path.dirname(game_versions[event.Data()]['debug_xgd']) emu.SetLogFile(os.path.join(crashdump_dir, LogFilename())) print 'loading layout...' emu.LoadMedia(game_versions[event.Data()]['debug_xgd']) print 'starting emulation...' emu.StartEmulation() self.AddEvent(['update_screen',self.currentmenu]) #event: place_order elif event.EventType() == 'place_order': TakeOrder(event.Data()) self.AddEvent(['update_screen',self.currentmenu]) #event:subst elif event.EventType() == 'subst': os.system('cls') print box_text('SubstDrive') for subst_cmd in event.Data(): SubstDrive(subst_cmd) os.system('pause') self.AddEvent(['update_screen', self.currentmenu]) elif event.EventType() == 'view_orders': ViewOrders(event.Data()) self.AddEvent(['update_screen', self.currentmenu]) elif event.EventType() == 'choose_date': self.AddMenu(OneWeekChoice(event.Data())) #event:run_batfile elif event.EventType() == 'run_batfile': run_batfile(event.Data()) self.AddEvent(['update_screen',self.currentmenu]) #event:konami_code elif event.EventType() == 'konami_code': print 'Press any key to play Gradius' wait_for_key() print 'You get TURTLETEST instead', print_slow_dots(5) self.AddMenu(TurtleTest()) self.AddEvent(['update_screen',self.currentmenu]) elif event.EventType() == 'final_event': self.final_event = event.Data() else: error_exit('Unhandled Event: '+'['+str(event.EventType())+'] [' +str(event.Data())+']') def OnSelectEvents(self,event): if event.EventType() is not 'on_select': error_exit('Somehow a non-on_select event got sent to ' 'OnSelectEvents(). Shouldn\'t happen!') def UpdateKeyHistory(self,key): if len(self.key_history) > 50: self.key_history.pop(0) self.key_history.append(key) def CheckCodes(self): code1 = ['CURSOR_UP', 'CURSOR_UP', 'CURSOR_DOWN', 'CURSOR_DOWN', 'CURSOR_LEFT', 'CURSOR_RIGHT', 'CURSOR_LEFT', 'CURSOR_RIGHT', 'b', 'a'] ## code2 = ['CURSOR_UP', ## 'CURSOR_DOWN', ## 'CURSOR_LEFT', ## 'CURSOR_RIGHT', ## 'a', ## 'b', ## 'x', ## 'y'] codes = [code1] for code in codes: if code == self.key_history[-len(code):]: self.AddEvent(['konami_code','']) def GamePage(self,game_id): items = [] if get_setting(game_id,'jimmylevels','NO_EXIT') != False: items.append(['Level select', 'jimmy_level', game_id, ('Choose a Jimmy level, then run %s, Version: %s' % (get_setting(game_id,'name'), GetVersionNumber(game_id)))]) if get_setting(game_id,'xex','NO_EXIT') != False: items.append(['Run %s' % get_setting(game_id,'name'), 'xex', game_id, ('Let\'s play %s, Version: %s!' % (get_setting(game_id,'name'), GetVersionNumber(game_id)))]) if get_setting(game_id,'self','NO_EXIT') != False: items.append(['Run %s' % get_setting(game_id,'name'), 'self', game_id, ('Let\'s play %s, Version: %s!' % (get_setting(game_id,'name'), GetVersionNumber(game_id)))]) if get_setting(game_id, 'switches', 'NO_EXIT') != False: items.append(['Manage Switches', 'manage_switches', game_id, ('Select switch to temporarily disable')]) if get_setting(game_id, 'set_home', 'NO_EXIT') != False: items.append(['Set PS3 Home Directory', 'set_home', game_versions[game_id], ('Set the PS3 home directory, then you can use ' 'game -> app_home in the xmb to load %s' % ( get_setting(game_id,'name')))]) if get_setting(game_id, 'cab_hash', 'NO_EXIT') != False: items.append(['Identify Version', 'identify_version', game_id, 'Check CAB or PKG version']) if get_setting(game_id,'xgd','NO_EXIT') != False: items.append(['Start Emulator', 'begin_emu', game_id, ('Start Xbox Disc Emulator with layout file %s' % game_versions[game_id]['xgd'])]) if get_setting(game_id, 'debug_xgd', 'NO_EXIT') != False: items.append(['Start Emulator (Debug)', 'begin_debug_emu', game_id, ('Start Xbox Disc Emulator with layout file %s' % game_versions[game_id]['debug_xgd'])]) if get_setting(game_id, 'lan_dlcnames', 'NO_EXIT') != False: items.append(['Select DLC', 'lan_select_dlc', game_id, 'Selectively disable DLC']) if get_setting(game_id,'logdestination','NO_EXIT') != False: items.append(['Copy logs to network', 'upload_logs', game_id, ('Copy %s logs to the network (%s)' % (get_setting(game_id,'name'), get_setting(game_id,'logdestination')))]) items.append(['Open network logs folder', 'open_log_folder', game_id, ('Open network logs folder (%s)' % get_setting(game_id,'logdestination'))]) ## GONE. Nobody used it. Thomson didn't keep the reference scripts up to date ## if get_setting(game_id,'script_local','NO_EXIT') != False: ## items.append(['Compare local script to network script', ## 'compare_scripts', ## game_id, ## ('Compare local scripts to reference scripts at %s' ## % get_setting(game_id,'script_remote'))]) if FindSocketPortPosition(game_id) is not False: items.append(['Modify Socketport', 'set_socket_port', game_id, ('Temporarily change the socketport. Socketport ' 'currently set to: %s' % CurrentSocketPort(game_id))]) if get_setting(game_id,'active_script','NO_EXIT') != False: items.append(['Script Manager', 'script_manager', game_id, 'Open the script manager that sometimes works! Yay!']) if get_setting(game_id,'cab_folder_source','NO_EXIT') != False and \ get_setting(game_id,'cab_folder_destination','NO_EXIT') != False: items.append(['Transfer CAB', 'cab_transfer', game_id, ('Transfer %s CAB file to Xbox 360' % get_setting(game_id,'name'))]) if 'no_cab_check' not in game_versions[game_id]: items.append(['Check 360 CAB version', 'check_cab_file', game_id, ('Check if the CAB file currently on your 360 matches' ' the cab file currently on your PC.')]) if get_setting(game_id, 'ps3_pkg', 'NO_EXIT') != False or \ get_setting(game_id, 'ps3_patch', 'NO_EXIT') != False: items.append(['Install PS3 Packages', 'pkg', game_id, ('Transfer %s PKG file to PS3' % get_setting(game_id, 'name'))]) if get_setting(game_id,'script_report','NO_EXIT') != False: items.append(['Script Report', 'script_report', game_id, ('EXPERIMENTAL: Attempt to identify the scripts ' 'currently in use')]) if get_setting(game_id,'title_update','NO_EXIT') != False: items.append(['Prepare For Emulation', 'prepare_for_emulation', game_id, ('Copy CAB file and TitleUpdate from local PC ' 'to 360.')]) if get_setting(game_id,'sync','NO_EXIT') != False: items.append(['Synchronize It!', 'syncit', game_id, ('Run Synchronize It! on project %s.\n\n Local Version: %s\nRemote Version: %s\n\nNote: To refresh version numbers, select "Back" then reselect "%s".' % (get_setting(game_id,'sync'), GetVersionNumber(game_id), GetVersionNumber(game_id, local=False), get_setting(game_id, 'name')))]) if get_setting(game_id,'wikipage','NO_EXIT') != False: items.append(['Open wiki page', 'wiki_page', game_id, ('Open "%s" on the QA Wiki' % get_setting(game_id,'wikipage'))]) if get_setting(game_id, 'run_batfile', 'NO_EXIT') != False: items.append([game_versions[game_id]['run_batfile'][0], 'run_batfile', game_versions[game_id]['run_batfile'][1], 'Run the file "%s"' % game_versions[game_id]['run_batfile'][1]]) if get_setting(game_id, 'subst', 'NO_EXIT') != False: items.append(['SubstDrive', 'subst', game_versions[game_id]['subst'], 'Run Subst with the paramaters: %s' % game_versions[game_id]['subst']]) if get_setting(game_id, 'shortcuts', 'NO_EXIT') != False: for sc_id in game_versions[game_id]['shortcuts']: items.append(['Shortcut: %s' % game_versions[sc_id]['name'], 'select_game_page', sc_id, 'Follow shortcut to %s' % game_versions[sc_id]['name']]) if get_setting(game_id, 'cat_shortcuts', 'NO_EXIT') != False: for sc_id in game_versions[game_id]['cat_shortcuts']: items.append(['Shortcut: %s' % sc_id, 'select_category', sc_id, 'Follow shortcut to category %s' % sc_id]) self.AddMenu(MenuMaker(get_setting(game_id,'name'),items)) def ChangeComment(self,event,comment): self.menu[event.SourceMenu()].active_items[event.MenuSelection()][3] = comment #self.menu[finger[0]].RefreshActiveItems() self.AddEvent(['update_screen',event.SourceMenu()]) class Event: def __init__(self, event_type, data, source, source_selection, delay): self.event_type = event_type self.data = data self.menu_source = source self.menu_selection = source_selection self.time_generated = time.clock() self.delay = delay def EventType(self): return self.event_type def Data(self): return self.data def TimeGenerated(self): return self.time_generated def Delay(self): if self.delay == 0: return 0 time_until_run = (self.TimeGenerated() + self.delay) - time.clock() if time_until_run <= 0: return 0 else: return time_until_run def SourceMenu(self): return self.menu_source def MenuSelection(self): return self.menu_selection def EventLogging(event): event_list = [event.EventType(), event.Data()] fingerprint = ['%.2f' % event.TimeGenerated(), '%.2f' % event.Delay(), event.SourceMenu()] return str(event_list)+str(fingerprint) def MiniMenu(heading,items,NO_BACK=False): minihandler = MenuHandler() minihandler.AddMenu(MenuMaker(heading, items)) if NO_BACK: minihandler.menu[0].RemoveBack() while minihandler.final_event == None: minihandler.ProcessEvent() return minihandler.final_event class TurtleTest: def __init__(self): self.menu_stack = [] self.x = 0 self.y = 0 #work out how to remove reliance on these self.selection = 0 self.NO_BACK = False self.turtle = 't' def ProcessKey(self,key): if key == 'CURSOR_UP': self.y -= 1 elif key == 'CURSOR_DOWN': self.y += 1 elif key == 'CURSOR_LEFT': self.x -= 1 elif key == 'CURSOR_RIGHT': self.x += 1 elif key.upper() == 'ESCAPE': self.AddEvent(['exit_query',self.menu_position]) else: return self.AddEvent(['update_screen',0]) def UpdateScreen(self): print os.system('cls') print '\n'*self.y print ' '*(self.x), print self.turtle def AddEvent(self,event,delay=0): event = Event(event[0], event[1], self.menu_position, self.selection, delay) self.menu_stack.append(event) def ListGames(): games = [] for game_id in game_versions.ListGIDs(): game = get_setting(game_id,'game') if game not in games: games.append(game) return games def ListGameIDs(game,category=None): game_ids = [] for game_id in game_versions.ListGIDs(): if get_setting(game_id,'game') == game: game_ids.append(game_id) return game_ids def GamesMenu(): games = ListGames() games.sort() items = [] for game in games: items.append([game, 'select_game', game, ('Good %s, %s. Would you like to play %s today?' %(time_of_day(),windows_username()[0],game))]) return MenuMaker('QA Menu',items) def OneGameMenu(game): game_ids = ListGameIDs(game) categories = [] for game_id in game_ids: category = get_setting(game_id,'category') if category not in categories: categories.append(category) categories.sort() items = [] for category in categories: items.append([category, 'select_category', category, ('Which type of %s would you like to play?' % game)]) return MenuMaker(game,items) def JimmyLevelSelect(game_id): if not get_setting(game_id,'jimmylevels','NO_EXIT'): error_exit('jimmylevels missing from game_id: %s' % game_id) levels = get_setting(game_id,'jimmylevels') list_switches = get_setting(game_id,'switches') switches = ' ' for switch in list_switches: switches += switch+' ' if get_setting(game_id,'self','NO_EXIT'): event_command = 'self_custom_switch' elif get_setting(game_id,'xex','NO_EXIT'): event_command = 'xex_custom_switch' items = [] for level in levels: custom_switches = switches+' -level='+level items.append([level, event_command, [game_id,custom_switches], 'Play %s in %s' % (level, get_setting(game_id,'name'))]) return MenuMaker('Level Select',items) def LANDLCMenu(game_id): if 'lan_dlcnames' not in game_versions[game_id]: error_exit('LANDLCMenu(): lan_dlcnames missing from game_id: %s' % game_id) if 'lan_dlcids' not in game_versions[game_id]: error_exit('LANDLCMenu(): lan_dlcids missing from game_id: %s' % game_id) if 'lan_dlc_disabled' not in game_versions[game_id]: game_versions[game_id]['lan_dlc_disabled'] = [] dlcstats = {} for dlcname in game_versions[game_id]['lan_dlcids']: if dlcname in game_versions[game_id]['lan_dlc_disabled']: dlcstats[dlcname] = False else: dlcstats[dlcname] = True longest_name = 0 for dlcname in game_versions[game_id]['lan_dlcnames']: if len(dlcname) > longest_name: longest_name = len(dlcname) longest_name += 2 items = [] for dlc, status in dlcstats.iteritems(): dlcname = game_versions[game_id]['lan_dlcnames'][ game_versions[game_id]['lan_dlcids'].index(dlc)] one_item = [] if status: one_item.append('%s (enabled)' % dlcname.ljust(longest_name)) else: one_item.append('%s (disabled)'% dlcname.ljust(longest_name)) one_item.append('lan_toggle_dlc') one_item.append([game_id, dlc]) if status: one_item.append('Press ENTER to disable %s (%s)' % (dlcname, dlc)) else: one_item.append('Press ENTER to enable %s (%s)' % (dlcname, dlc)) items.append(one_item) items.sort() return MenuMaker('DLC Select', items) def GetLANSwitches(game_id): if 'lan_dlc_disabled' not in game_versions[game_id]: if 'switches' in game_versions[game_id]: return game_versions[game_id]['switches'] else: return [] if len(game_versions[game_id]['lan_dlc_disabled']) == 0: if 'switches' in game_versions[game_id]: return game_versions[game_id]['switches'] else: return [] nodlc = '--nodlc %s' dlc_str = '' for dlc in game_versions[game_id]['lan_dlc_disabled']: dlc_str += '%s ' % dlc if 'switches' in game_versions[game_id]: switches = copy.deepcopy(game_versions[game_id]['switches']) else: switches = [] switches.append(nodlc % dlc_str) return switches def FindSocketPortPosition(game_id): if 'switches' not in game_versions[game_id]: return False switches = game_versions[game_id].GetRawSetting('switches') switchstart = switches.find('-socketport') if switchstart == -1: return False eq_pos = switches[switchstart:].find('=') + switchstart #remove whitespace, then find the end of the number number_end = switches[eq_pos+1:].strip().find(',') + eq_pos+1 return [switchstart,number_end] def ModifySocketPort(game_id, newport): old_switches = game_versions[game_id].GetRawSetting('switches') if FindSocketPortPosition(game_id) is False: new_switches = old_switches + ', -socketport='+str(newport) else: pos = FindSocketPortPosition(game_id) new_switches = (old_switches[:pos[0]] + ' -socketport='+str(newport)+ old_switches[pos[1]:]) game_versions[game_id]['switches'] = new_switches def CurrentSocketPort(game_id): if 'switches' not in game_versions[game_id]: return 'Socketport Not Set' if FindSocketPortPosition(game_id) is False: return 'Socketport Not Set' switches = game_versions[game_id].GetRawSetting('switches') pos = FindSocketPortPosition(game_id) pos[0] += len('-socketport') return switches[pos[0]:pos[1]].strip(' = ') def SetSocketPort(game_id): current_tx = 'Current SocketPort:' new_tx = 'Enter New SocketPort:' print current_tx.rjust(len(new_tx)), CurrentSocketPort(game_id) new_port = raw_input(new_tx+' ') while not new_port.isdigit(): print 'Please only use numbers, not "%s"' %new_port new_port = raw_input(new_tx+' ') ModifySocketPort(game_id,new_port) def GetSwitchesMenu(game_id, enable): if '__static_switches__' not in game_id: game_id['__static_switches__'] = game_id['switches'] if enable: event = 'enable_switch' switches_source = 'disabled_switches' title = 'Enable Switch' elif not enable: event = 'disable_switch' switches_source = 'switches' title = 'Disable Switch' items = [] for idx, switch in enumerate(game_id[switches_source]): items.append([switch, event, [game_id.gid, idx], 'Temporarily remove the "%s" switch' % switch]) return MenuMaker(title, items) def GetVersionNumber(game_id, local=True): if 'cab_hash' in game_versions[game_id]: #return HashVersion(game_id) return 'CAB \\ PKG' if local: if 'version_file' not in game_versions[game_id]: return 'Unknown' else: if 'sync_version_file' not in game_versions[game_id]: return 'Unknown' if local: version_path = game_versions[game_id]['version_file'] else: version_path = game_versions[game_id]['sync_version_file'] if not os.path.exists(version_path): return 'Unknown' v_file = open(version_path,'r') store_next = False version = 'Unknown' for line in v_file: if store_next: version = line break #GTA IV condition: if line.startswith('[VERSION_NUMBER]'): store_next = True #e1 / e2 condition if line.startswith('[EPISODE_VERSION_NUMBER]'): store_next = True #rdr2 condition if 'gametype' in game_versions[game_id]: if game_versions[game_id]['gametype'] == 'rdr2': return line.strip('\n') #lan condition if 'gametype' in game_versions[game_id]: if game_versions[game_id]['gametype'] == 'LAN': return line.strip('\r\n') return version.strip('\n') def VersionText(text,game_id): version = GetVersionNumber(game_id) if version == 'Unknown': return '' def HashVersion(game_id): if 'cab_folder_source' not in game_versions[game_id]: return 'Unknown' UpdateHashes() if game_versions[game_id]['cab_hash'] not in settings: return 'Unknown' local_hash = FileHash(game_versions[game_id]['cab_folder_source']) if local_hash in settings[game_versions[game_id]['cab_hash']]: return settings[game_versions[game_id]['cab_hash']][local_hash] else: return 'Unknown' def IdentifyVersionHash(gid): if 'cab_folder_source' in gid: filename = gid['cab_folder_source'] elif 'ps3_pkg' in gid: filename = gid['ps3_pkg'] else: return False UpdateHashes() if 'cab_hash' not in gid: return False if gid['cab_hash'] not in settings: return False hasher = HashScreen(filename) if hasher.hash in settings[gid['cab_hash']]: return settings[gid['cab_hash']][hasher.hash] else: return False class CommentBox: def __init__(self): self.comments = [] self.display_lines = 5 self.display_width = 75 self.display_position = 0 def __call__(self): ## cstring = '' ## for comment in self.comments: ## cstring += str(comment)+'\n' ## return cstring return self.GetDisplayComments() def AddComment(self,comment): #self.comments.append(word_wrap(comment,self.display_width)) split = word_wrap(comment, self.display_width).strip('\n').split('\n') self.comments.extend(split) if len(self.comments) - 1 > self.display_lines: self.display_position = (len(self.comments)) - self.display_lines def GetDisplayComments(self): if len(self.comments) < self.display_lines: return self.FormatDisplayComments(self.comments) start_line = self.display_position#len(self.comments) - self.display_lines end_line = self.display_position + self.display_lines return box_text(self.FormatDisplayComments(self.comments[start_line:end_line])) def FormatDisplayComments(self, comments): cstring = '' for comment in comments: cstring += str(comment)+'\n' return cstring.strip('\n') def CommentsBelow(self): if len(self.comments) > self.display_position + self.display_lines: return True else: return False def CommentsAbove(self): if self.display_position is 0: return False else: return True def MoveUp(self): if self.CommentsAbove(): self.display_position -= 1 def MoveDown(self): if self.CommentsBelow(): self.display_position += 1 def CheckDumpEnv(): """ check for the rage_crashdump_dir environment variable, warn if it isn't found. Then check for the directory it refers to and create it if it isn't found """ rage_env = 'RAGE_CRASHDUMP_DIR' dump_dir = os.getenv(rage_env) if dump_dir == None: print box_text('WARNING: Environment variable %s has not been set. ' 'Dumps may not be created correctly. Please check ' 'with your lead.' % rage_env) print box_text('Press any key to continue') wait_for_key() return False if not os.path.exists(dump_dir): print 'Dump directory not found, attempting to create "%s"' % dump_dir drive = os.path.splitdrive(dump_dir)[0] if not drive == '': if not os.path.exists(drive): error_exit('Attempting to create %s, drive not found: "%s"' % (rage_env,drive)) os.makedirs(dump_dir) elif not os.path.isdir(dump_dir): error_exit('The dump directory specified in %s appears to be a file.' % rage_env) def GIDtoString(gid): final_string = '['+gid.gid+']\n' for settingname in gid.ListSettings(): setting = gid.GetRawSetting(settingname) if settingname in gid.lists: line = 'LIST: ' else: line = '' #line += settingname + ' = ' + str(setting) + '\n' line += '%s = %s\n' % (settingname, setting) final_string += line return final_string def WriteAllGIDs(gid_holder,fname='allgids.ini'): outfile = open(fname,'w') for gid in gid_holder: outfile.write(GIDtoString(gid)) outfile.write('\n\n\n') outfile.close() def ActiveProfiles(): target = 'hdd:\\Content\\' folders = xbdir_list(target, directories = True) profile_folders = [] for index, folder in enumerate(folders): if folder[0] != '0000000000000000': profile_folders.append(folder) return profile_folders def CountGTASaves(profile): target = 'hdd:\\Content\\' game = '545407f2' profile = os.path.join(target, profile) profile_folders = xbdir_list(profile, directories=True) game_folders = [] for folder in profile_folders: game_folders.append(folder[0]) if game.upper() not in game_folders: return 0 save_folder = os.path.join(profile,game) save_folder = os.path.join(save_folder,'00000001') saves_found = 0 for fname in xbdir_list(save_folder): if fname[0].startswith('SGTA'): saves_found += 1 return saves_found def SavesInProfiles(): """ return pretty string saying how many saves in how many profiles """ savesfound = 0 profilesfound = 0 for profile in ActiveProfiles(): profilesfound += 1 savesfound += CountGTASaves(profile[0]) if savesfound == 1: saveword = 'save' else: saveword = 'saves' if profilesfound == 1: profileword = 'profile' else: profileword = 'profiles' return '%s %s found in %s %s' % (savesfound, saveword, profilesfound, profileword) def XBCopyTree(source, destination, newer_only=False, verbose=True): """copy all files in a directory and all it's subdirectories to the xbox""" debug=False logging('XBCopyTree called on "%s"' % source) #see if we're looking for a wildcard if os.path.basename(source).startswith('*.'): if debug: print 'wildcard found' wild_extension = os.path.basename(source).lstrip('*.') wildcard = True source = os.path.dirname(source) if debug: print 'wildcard:',wild_extension else: wildcard = False #exit if we can't find the source if not os.path.exists(source): error_exit('XBCopyTree called on a source that doesn\'t exist: "%s"' % source) #short-circuit to XBCopy if we're only copying a single file if os.path.isfile(source): if debug: print 'Copying a single file' XBCopy(source, destination , newer_only=newer_only, verbose=verbose) return True #make sure our destination is a directory if not destination.endswith('\\'): destination += '\\' if debug: print 'Appending \\ to destination' #generate a list of source/destination pairs transfer_list = [] for root, dirs, files in os.walk(source): for filename in files: if wildcard: if not filename.endswith(wild_extension): continue transfer_item = [None,None] transfer_item[0] = os.path.join(root,filename) dest_path = root.replace(source,'').lstrip('\\') if not dest_path == '': dest_path += '\\' if debug: print 'dest_path',dest_path transfer_item[1] = destination + dest_path if debug: print transfer_item transfer_list.append(transfer_item) #iterate through the list of files to transfer for item in transfer_list: XBCopy(item[0], item[1], newer_only=newer_only, verbose=verbose) def XBCopy(source, destination, recursive=True, newer_only=False, verbose=True): """Copy a single file to the default xbox""" debug=False debug_log=False if not destination.endswith('\\'): destination += '\\' logging('XBCopy: Copying "%s" to "%s"' % (source, destination)) if not os.path.exists(source): error_exit('XBCopy called on a source that doesn\'t exist: "%s"' % source) if not os.path.isfile(source): error_exit('XBCopy called on a source that isn\'t a file: "%s"' %source) xdk_vars() #prepare to use xbox sdk switches = ['/H','/T','/Y'] if recursive: switches.append('/R') if newer_only: switches.append('/D') #add the files to the end of the argument, source then dest switches.append(source) switches.append(destination) full_args = ['xbcp.exe'] full_args.extend(switches) if debug: print 'full_args:',full_args if newer_only: copy_message = 'Copying "%s" to "%s" only if source is newer' else: copy_message = 'Copying "%s" to "%s"' if verbose: print word_wrap(copy_message % (source, destination)).rstrip('\n '), copier = subprocess.Popen(full_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out = copier.communicate() if debug_log: logging('err: '+out[1]+', stdout: '+out[0]) if len(out[1]) == 0: if verbose: print '... success!' logging('XBCopy: File copy appears successful') else: if verbose: print '... failure!' err_string = out[1] error_exit('XBCopy failed with this message: %s' % err_string) if debug: print 'err:',out[1],'stdout:', out[0] def XBDel(target): """ Delete the target from the xbox """ args = ['xbdel.exe','/F','/R','/H',target] print 'Deleting "%s" from Xbox' % target, logging('XBDel: Deleting "%s"' % target) deleter = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out = deleter.communicate() if len(out[1]) == 0: print '... success!' return True else: if out[1].startswith('xbdel: No such file exists'): print '... success!' return True elif 'does not exist' in out[1]: print '... success!' return True print '... failure!' error_exit('XBDel: Failed to erase "%s" from Xbox, because: %s' % (target,out[1])) def missiontime(statsfile='teeoff.pstats'): try: pstats = split_pstats(open(statsfile,'r').readline()) except IOError: print 'ERROR: File not found' wait_for_key() return False mission_name = '' mission_end_time = -1 mission_start_time = -1 on_mission = False time_in_cutscenes = 0 cutscene_start = 0 cutscene_end = 0 current_cut = '' pause_start = 0 pause_end = 0 pause_time = 0 for position,stat in enumerate(reversed(pstats)): if 'psid' in stat: if stat['psid'] == 'MISSION_PASSED': mission_name = stat['name'] mission_end_time = stat['time'] print '%s ended at %s' % (stat['name'],stat['time']) mission_end_pos = position on_mission = True if mission_start_time == -1: if stat['psid'] == 'MISSION_STARTED': if stat['name'] == mission_name: print '%s started at %s' % (stat['name'],stat['time']) mission_start_time = stat['time'] mission_start_pos = position on_mission = False break else: print 'problem tracking mission, mission in progress?' return False if stat['psid'] == 'CUTSCENE_SKIPPED' or \ stat['psid'] == 'CUTSCENE_ENDED': if cutscene_end == 0: cutscene_end = int(stat['time']) current_cut = stat['name'] if stat['psid'] == 'CUTSCENE_STARTED': cutscene_start = int(stat['time']) if cutscene_end < cutscene_start: cutscene_end = 0 cutscene_start = 0 print 'problem tracking cutscene, end smaller than start' elif current_cut != stat['name']: print 'problem tracking cutscene, name change' print ('thought i was tracking %s, now on %s' % (current_cut, stat['name'])) else: time_in_cutscenes += cutscene_end - cutscene_start cutscene_end = 0 cutscene_start = 0 if on_mission: if stat['psid'] == 'GAME_UNPAUSED': #print 'game unpaused at %s' % stat['time'] pause_end = int(stat['time']) if stat['psid'] == 'GAME_PAUSED': #print 'game paused at %s' % stat['time'] pause_start = int(stat['time']) if pause_end == 0: print ('problem tracking pause time, pause without ' 'unpause') else: pause_time += pause_end - pause_start #print 'pause time now %s' % pause_time if mission_end_time != -1 and mission_start_time != -1: mission_time = int(mission_end_time) - int(mission_start_time) print 'Mission Name:',mission_name print 'Mission Time:',DisplayTime(mission_time) print ' Cut Time:',DisplayTime(time_in_cutscenes) print ' Pause Time:',DisplayTime(pause_time) print '=========================' print 'Overall Time:',DisplayTime(mission_time-time_in_cutscenes-pause_time) else: print 'last mission not found' wait_for_key() return False return pstats[mission_start_pos:mission_end_pos] def ConvertTime(seconds): hours = seconds / (60*60) minutes = (seconds / 60) - (hours*60) seconds = seconds - (hours*60*60) - (minutes*60) return hours, minutes, seconds def DisplayTime(seconds): return '%02dh %02dm %02ds' % ConvertTime(seconds) def FileHash(filename, blocksize=1024*8, verbose=False): """ Generate a hash from the supplied file """ hasher = hashlib.md5() logging('FileHash started, file: "%s", blocksize: "%s"' % (filename, blocksize)) if verbose: print 'Opening "%s" for hashing' % filename #this is probably really really bad, accidentally left it on ascii instead #of binary. seems to still be working at least for internal consistency #but that is worrisome. binary hashing was slower by at least tenfold. try: hashfile = open(filename,'r') except IOError: logging('FileHash: Unable to open "%s" for hashing' % filename) return False while True: data = hashfile.read(blocksize) if not data: break hasher.update(data) #print hasher.hexdigest() ## hasher.update(hashfile.read()) digest = hasher.hexdigest() logging('FileHash complete: %s' % digest) if verbose: print 'hash complete: %s' % digest return digest def UpdateHashes(): """ Update settings with cab hashes grabbed off the network """ if '-focus' in command_line_switches(): return False for gid in settings.ListGIDs(): if gid.startswith('h_'): del settings[gid] if not os.path.exists(settings['defaults']['cab_hashes']): return False try: settings.LoadFile(settings['defaults']['cab_hashes']) except IOError: logging('UpdateHashes: Error attempting to read %s' % settings['defaults']['cab_hashes']) return False settings.DoStringReplacement(settings['variables']) class XBDiscEmulator: def __init__(self): self.PID = '' self.PIDmarker = 'ProcessId = ' self.exe = 'xbEmulate.exe' def StartEmulator(self): xdk_vars() try: emu = subprocess.Popen(self.exe, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except WindowsError: error_exit('XBDiscEmulator: Error trying to load xbEmulate.exe. ' 'Your Xbox SDK may require updating.') emu_response = emu.communicate() pid_pos = emu_response[0].find(self.PIDmarker) if pid_pos == -1: error_exit('XBDiscEmulator: Unable to determine process ID of disc ' 'emulator') self.PID = emu_response[0][pid_pos+len(self.PIDmarker):].strip('\n\r') logging('XBDiscEmulator: Emulator started with PID %s' % self.PID) def SendCommand(self,command): args = [self.exe,'/nologo','/process',self.PID] args.extend(command) if self.PID == 0: error_exit('XBDiscEmulator: Emulator has not been started. Emulator' ' must be started before commands can be sent to it.') if not IsPIDRunning(self.PID): error_exit('XBDiscEmulator: SendCommand tried to send a command ' 'to a dead emulator') try: emu = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except WindowsError: error_exit('XBDiscEmulator: Error trying to load xbEmulate.exe. ' 'Your Xbox SDK may require updating.') #TODO: parse emu.communicate() to get errors and check em #strange: errors don't seem to appear on stderr. thuddingly bad option: emu_response = emu.communicate() if 'ERROR' in emu_response[0]: error_exit('XBDiscEmulator: MYSTERY ERROR: "%s"' % emu_response[0]) return emu_response def LoadMedia(self,filename): #todo: check for file before trying to use it logging('XBDiscEmulator: Loading media from "%s"' % filename) self.SendCommand(['/media',filename]) def GUIminimize(self): self.SendCommand(['/minimize']) def GUIrestore(self): self.SendCommand(['/restore']) def QueryEmulator(self): result = self.SendCommand(['/query']) split = result[0].split('\r\n') results_dict = {} for item in split: if ':' in item: item_split = item.split(':') results_dict[item_split[0]] = item_split[1].strip() return results_dict def SetLogFile(self, filepath): #todo: check for and erase logfile, etc logging('XBDiscEmulator: Setting log file to "%s"' % filepath) self.SendCommand(['/log',filepath]) def StartEmulation(self): self.SendCommand(['/emulate','start']) def LogFilename(): time_string = time.strftime('%Y%m%d_%H_%M_%S') return 'emu_%s_%s.log' % (os.environ.get('username'), time_string) def ScriptReport(report_file): logging('ScriptReport: Generating report from %s' % report_file) report = SettingsLoader() report.LoadFile(report_file) final_report = [] for script in report['default']['scripts']: current_hash = FileHash(report[script]['location']) script_name = 'Unknown' for script_hash in report[script]['scripts']: if current_hash == report[script][script_hash][1]: script_name = report[script][script_hash][0] final_report.append('%s: %s' % (report[script]['name'],script_name)) final_string = '' for detail in final_report: final_string += detail final_string += '\n' return final_string # WHY: average time calculations seem wrong, dunno wwwwwhhhyyyyyyy class CopyFile: def __init__(self, source, destination): #TODO: check source exists, destination writable self.blocksize = 1024*1024 self.current_block = 0 self.time_copying = 0 self.destination = destination self.filesize = int(os.stat(source).st_size) self.bytes_copied = 0 self.src_stat = os.stat(source) self.src_data = open(source, 'rb') self.dst_data = open(destination, 'wb') self.file_copied = False self.speed = 0 self.all_speeds = 0 self.speed_samples = 0 self.average_speed = 0 def CopyNextBlock(self): block_start = time.clock() copy_buffer = self.src_data.read(self.blocksize) if copy_buffer: self.dst_data.write(copy_buffer) self.current_block += 1 current_block_size = len(copy_buffer) self.bytes_copied += current_block_size block_stop = time.clock() self.time_copying += (block_stop - block_start) self.UpdateSpeed() else: if not self.file_copied: self.CopyComplete() def CopyComplete(self): self.file_copied = True self.src_data.close() self.dst_data.close() #set destination atime and mtime to sources amtime = (self.src_stat.st_atime, self.src_stat.st_mtime) os.utime(self.destination, amtime) def OnAbort(self): self.src_data.close() self.dst_data.close() def PercentageCopied(self): try: return (1.0 * self.bytes_copied / self.filesize) * 100 except ZeroDivisionError: return 100 def UpdateSpeed(self): ## copy_time = stop - start ## print size ## print copy_time ## self.speed = 1.0*size / copy_time ## print self.speed ## self.all_speeds += self.speed ## self.speed_samples += 1 ## raw_input() #print self.bytes_copied, '/', self.time_copying self.average_speed = 1.0*self.bytes_copied / self.time_copying #print self.average_speed #raw_input() def AverageSpeed(self): pass class CopyScreen: def __init__(self, source, destination): self.copier = CopyFile(source, destination) self.fname = os.path.basename(source) self.start = time.clock() self.elapsed = 0 while not self.copier.file_copied: self.elapsed = time.clock() - self.start self.UpdateScreen() self.copier.CopyNextBlock() def UpdateScreen(self): percentage = self.copier.PercentageCopied() #speed = self.copier.AverageSpeed() / (1024*1024) os.system('cls') print ' File: %s' % self.fname print ' Progress: %d%%' % percentage print ' Speed: %d MB\\s' % (self.copier.average_speed / (1024*1024)) print 'Time Elapsed: %d' % self.elapsed print ' Block Speed: %d' % self.copier.speed def PS3SetFSDir(directory): """ use ps3run to set the fileserve directory on the default ps3 """ ps3run = subprocess.Popen(['ps3run','-f'+directory], stdout=subprocess.PIPE, stderr=subprocess.PIPE) print ps3run.communicate()[0] def PS3InstallPKG(gid): """ remember: pass me a gid object, not a gid string """ to_install = [] if 'ps3_patch' in gid: to_install.append(gid['ps3_patch']) if 'ps3_pkg' in gid: to_install.append(gid['ps3_pkg']) pkg_installed = 0 for pkg in to_install: if pkg.endswith('pkg'): pkg_name = os.path.basename(pkg) pkg_path = os.path.dirname(pkg) else: pkg_name = 'Unknown' pkg_path = pkg print word_wrap('Preparing to install package: %s' % pkg_name) print word_wrap('Press any key to continue.') wait_for_key() PS3SetFSDir(pkg_path) print word_wrap('From the XMB, please select "Game -> * Install Packag' 'e Files -> %s" and press any key to continue.' % pkg_name) wait_for_key() print word_wrap('Please wait for installation to complete, then press ' 'any key to continue.') wait_for_key() pkg_installed += 1 print word_wrap('%s of %s package(s) installed, press any key to ' 'continue' % (pkg_installed, len(to_install))) wait_for_key() os.system('cls') def ProgressBar(percent, width=74): """Print a progress bar!""" #can't have more than 100%! if percent > 100: percent = 100 #or less than zero if percent < 0: percent = 0 #if the width is greater than 74, it's too big for the screen and messes up if width > 74: width = 74 one_box = 100.0 / width boxes = percent / one_box boxchar = chr(219) #spacers = ' '*int(width-boxes) bar = boxchar*int(boxes) spacers = ' '*(width-len(bar)) return box_text(bar+spacers) def RemoveDirectory(target): if not os.path.exists(target): return False target_walk = os.walk(target, topdown=False) for dirpath, dirnames, filenames in target_walk: for fname in filenames: os.remove(os.path.join(dirpath, fname)) os.rmdir(dirpath) def FancyCopyFolder(source, destination): if not os.path.exists(source): return False if not os.path.exists(destination): os.makedirs(destination) else: RemoveDirectory(destination) os.makedirs(destination) file_list = [] destinations = [] for dirpath, dirnames, filenames in os.walk(source): destination_folder = os.path.join(destination, dirpath.replace(source,'').strip('\\')) if not os.path.exists(destination_folder): os.mkdir(destination_folder) for fname in filenames: path_pair = [os.path.join(dirpath, fname), os.path.join(destination_folder, fname)] file_list.append(path_pair) FancyCopyFiles2(file_list) class FancyCopyFiles2: def __init__(self, file_list, title='Copying Files'): self.title = title self.destination = '' self.last_update = time.clock() self.overall_percentage = 0 self.total_size = 0 self.total_bytes_copied = 0 self.total_files = len(file_list) self.current_filename = '' self.current_filenumber = 0 self.current_file_percentage = 0 for fname in file_list: self.total_size += os.stat(fname[0]).st_size for index, fname in enumerate(file_list): self.destination = os.path.dirname(fname[0]) self.UpdateScreen(force=True) self.current_filenumber = index+1 self.current_filename = os.path.basename(fname[0]) self.CopyFile(fname[0], fname[1]) try: self.overall_percentage = (1.0 * self.total_bytes_copied / self.total_size) * 100 except ZeroDivisionError: self.overall_percentage = 100 self.UpdateScreen(force=True) def CopyFile(self, fname, destination, overwrite=True): self.UpdateScreen() #destination = os.path.join(self.destination, os.path.basename(fname)) if os.path.exists(destination): if overwrite: os.remove(destination) elif not overwrite: destination = self.IncrementFilename(destination) copier = CopyFile(fname, destination) while not copier.file_copied: copier.CopyNextBlock() self.current_file_percentage = copier.PercentageCopied() self.overall_percentage = (1.0 * (self.total_bytes_copied + copier.bytes_copied) / self.total_size) * 100 self.UpdateScreen() self.total_bytes_copied += copier.bytes_copied def IncrementFilename(self, dest): final_dest = dest increment = 0 while os.path.exists(final_dest): increment += 1 fname = os.path.splitext(os.path.basename(dest)) new_fname = '%s (%s)%s' % (fname[0], increment, fname[1]) final_dest = os.path.join(os.path.dirname(dest), new_fname) return final_dest def UpdateScreen(self, force=False): if (1.0* time.clock()) - self.last_update < 0.5: if not force: return False os.system('cls') print box_text(self.title,1) print '\n' print 'Copying File %s of %s to "%s"' % (self.current_filenumber, self.total_files, self.destination) print ProgressBar(self.overall_percentage) print '\n' print 'Copying "%s"' % self.current_filename print ProgressBar(self.current_file_percentage) self.last_update = time.clock() class FancyCopyFiles: def __init__(self, file_list, destination, overwrite=False, title='Upload Logs'): self.title = title self.destination = destination self.last_update = time.clock() self.overall_percentage = 0 self.total_size = 0 self.total_bytes_copied = 0 self.total_files = len(file_list) self.current_filename = '' self.current_filenumber = 0 self.current_file_percentage = 0 for fname in file_list: self.total_size += os.stat(fname).st_size for index, fname in enumerate(file_list): self.UpdateScreen(force=True) self.current_filenumber = index+1 self.current_filename = os.path.basename(fname) self.CopyFile(fname, overwrite) try: self.overall_percentage = (1.0 * self.total_bytes_copied / self.total_size) * 100 except ZeroDivisionError: self.overall_percentage = 100 self.UpdateScreen(force=True) def CopyFile(self, fname, overwrite=False): self.UpdateScreen() destination = os.path.join(self.destination, os.path.basename(fname)) if os.path.exists(destination): if overwrite: os.remove(destination) elif not overwrite: destination = self.IncrementFilename(destination) copier = CopyFile(fname, destination) while not copier.file_copied: copier.CopyNextBlock() self.current_file_percentage = copier.PercentageCopied() self.overall_percentage = (1.0 * (self.total_bytes_copied + copier.bytes_copied) / self.total_size) * 100 self.UpdateScreen() self.total_bytes_copied += copier.bytes_copied def IncrementFilename(self, dest): final_dest = dest increment = 0 while os.path.exists(final_dest): increment += 1 fname = os.path.splitext(os.path.basename(dest)) new_fname = '%s (%s)%s' % (fname[0], increment, fname[1]) final_dest = os.path.join(os.path.dirname(dest), new_fname) return final_dest def UpdateScreen(self, force=False): if (1.0* time.clock()) - self.last_update < 0.5: if not force: return False os.system('cls') print box_text(self.title,1) print '\n' print 'Copying File %s of %s to "%s"' % (self.current_filenumber, self.total_files, self.destination) print ProgressBar(self.overall_percentage) print '\n' print 'Copying "%s"' % self.current_filename print ProgressBar(self.current_file_percentage) self.last_update = time.clock() def DynamicProgramFiles(settings): """ replace %programfiles% with the env value """ programfiles = os.environ.get('programfiles') programfiles86 = os.environ.get('PROGRAMFILES(X86)') for setting in settings['defaults']: if settings['defaults'].GetRawSetting(setting).startswith('%programfiles%'): raw_setting = settings['defaults'].GetRawSetting(setting) new_setting = '%s\\%s' % (programfiles, raw_setting[15:]) logging('DynamicProgramFiles: Setting %s to %s' % ( setting, new_setting)) if programfiles86 != None: if not os.path.exists(new_setting): new_setting86 = '%s\\%s' % (programfiles86, raw_setting[15:]) logging('DynamicProgramFiles: %s not found, setting to %s' % ( new_setting, new_setting86)) new_setting = new_setting86 settings['defaults'][setting] = new_setting class MD5Hash: def __init__(self, filename): self.filename = filename self.blocksize = 8192 self.bytes_hashed = 0 self.hasher = hashlib.md5() try: self.data = open(filename, 'rb') except IOError, WindowsError: error_exit('MD5Hash: IOError when trying to open file for ' 'hashing: "%s"' % filename) self.file_hashed = False self.total_bytes = int(os.stat(filename).st_size) self.start_time = time.clock() self.stop_time = -1 def NextBlock(self): if self.file_hashed: return False hash_buffer = self.data.read(self.blocksize) if hash_buffer: self.hasher.update(hash_buffer) self.bytes_hashed += len(hash_buffer) else: if not self.file_hashed: self.HashComplete() def HashComplete(self): self.file_hashed = True self.data.close() self.stop_time = time.clock() logging('MD5Hash: Hashing performed on "%s". Result: %s' % ( self.filename, self.FileHash())) def PercentageHashed(self): return (1.0 * self.bytes_hashed / self.total_bytes) * 100 def FileHash(self): return self.hasher.hexdigest() class HashScreen: def __init__(self, filename): self.filename = filename self.hasher = MD5Hash(filename) self.last_update = time.clock() self.hash = None self.HashFile() self.UpdateScreen(force=True) self.hash = self.hasher.FileHash() def HashFile(self): self.UpdateScreen() while not self.hasher.file_hashed: self.hasher.NextBlock() self.UpdateScreen() def UpdateScreen(self, force=False): if (1.0 * time.clock()) - self.last_update < 0.5: if not force: return False os.system('cls') print box_text('Generate MD5 Hash',1) print '\n' print 'Generating MD5 Hash of "%s"' % os.path.basename(self.filename) print ProgressBar(self.hasher.PercentageHashed()) print 'Time Elapsed: %sh %sm %ss' % ( ConvertTime(int(time.clock() - self.hasher.start_time))) self.last_update = time.clock() def IdentifyVersionScreen(gid): start_time = time.clock() version = IdentifyVersionHash(gid) stop_time = time.clock() if version: print '\nVersion is:\n %s\n' % version else: print '\nUnable to identify version' print '\nPress any key to return' wait_for_key() #======================================================= class OrderGen: def __init__(self, missions, use_flow): self.missions = missions self.use_flow = use_flow print 'ordergen started, use flow: %s' % use_flow self.played = [] self.available = [] self.remaining = [] self.needs = {} self.order_digits = [] self.valid_path = True self.walking_path = False self.path_to_walk = [] #initialisation to_ignore = ['info'] if 'info' in self.missions: if 'to_ignore' in self.missions['info']: for ignore_id in self.missions['info']['to_ignore']: to_ignore.append(ignore_id) print 'ignore list:', str(to_ignore) for gid in self.missions: if gid.gid in to_ignore: continue if 'category' not in gid: gid['category'] = 'uncategorised' if 'available' in gid: if gid['available'] == 'yes': self.available.append(gid.gid) else: self.remaining.append(gid.gid) else: self.remaining.append(gid.gid) if use_flow: print 'using flow' self.GenerateNeeds() else: print 'ignoring flow' self.available.extend(self.remaining) self.remaining = [] for gid in self.available: self.needs[gid] = [] self.PopulateAvailableMissions() def PopulateAvailableMissions(self): self.available_missions = [] for mission_id in self.available: self.available_missions.append(self.missions[mission_id]) def GetAvailableMissions(self): ## start = time.clock() ## missions = [] ## for mission_id in self.available: ## missions.append(self.missions[mission_id]) ## ## end = time.clock() ## print 'GetAvailableMissions() completed in %s' % (end-start) return self.available_missions def PopMission(self, mission_id): for key, mission in enumerate(self.available_missions): if mission.gid == mission_id: self.available_missions.pop(key) return True print 'PopMission couldn\'t find mission' def CountAvailableMissions(self): return len(self.available) def CountMissionsLeft(self): return len(self.remaining) def GenerateNeeds(self): for gid in self.missions: if 'unlocks' in gid: for mission_id in gid['unlocks']: #print '%s needs %s' % (mission_id, gid.gid) if mission_id not in self.needs: self.needs[mission_id] = [] self.needs[mission_id].append(gid.gid) def ChooseNextMission(self, choice=-1): time_start = time.clock() if self.CountAvailableMissions() == 0: if self.CountMissionsLeft() == 0: error_exit('ChooseNextMission() called with no missions left') else: self.DumpUnusedMissions() error_exit('Missions are left, but none are available. This may' 'be caused by bad mission data.') if choice == -1: next_mission_id = random.randint(0, self.CountAvailableMissions()-1) else: next_mission_id = choice try: mission_selected = self.available.pop(next_mission_id) except IndexError: self.valid_path = False self.available = [] self.remaining = [] print ('tried to choose mission %s but only %s missions are ' 'available' % ( choice, self.CountAvailableMissions())) return False print 'mission selected:', next_mission_id, mission_selected self.PopMission(mission_selected) self.order_digits.append(next_mission_id) self.played.append(mission_selected) time_end = time.clock() # print 'ChooseNextMission() completed in %s' % (time_end-time_start) start = time.clock() self.UnlockMissions(mission_selected) end = time.clock() # print 'UnlockMissions() completed in %s' % (end-start) def UnlockMissions(self, mission_selected): selected_gid = self.missions[mission_selected] if 'unlocks' not in selected_gid: return False if not self.use_flow: return False for unlock_id in selected_gid['unlocks']: #check to see if all the requirements for a mission have been #fulfilled needs_met = 0 for need in self.needs[unlock_id]: if need in self.played: needs_met += 1 if needs_met == len(self.needs[unlock_id]): print 'All requirements for %s met, unlocking' % unlock_id self.available.append(unlock_id) self.remaining.remove(unlock_id) self.available_missions.append(self.missions[unlock_id]) def DumpUnusedMissions(self): out = open('gen_dump.txt', 'w') out.write('Missions Available (%s)\n' % len(self.available)) for m in self.available: out.write('%s\n' % m) out.write('\nRemaining Missions (%s)\n' % len(self.remaining)) for m in self.remaining: out.write('%s\n' % m) out.write('\nDumping Needs:\n') for key, value in self.needs.iteritems(): out.write('[%s]\n' '%s\n\n' % (key, value)) out.close() def GetSignature(self): sig_list = [] for num in self.order_digits: sig_list.append(self.NumToAlpha(num)) sig = '' last_element = '' recur = 0 for element in sig_list: if element == last_element: recur += 1 elif element != last_element: if recur != 0: sig += '%s' % recur recur = 0 last_element = element sig += element if recur != 0: sig += '%s' % recur #selfcheck sig_len = len(sig) sig = '%sl%s' % (sig_len, sig) return sig def NumToAlpha(self, num): sep = '|' alpha = string.ascii_letters max_num = len(string.ascii_letters) - 1 repeats = 0 if num > max_num: repeats = int(num / max_num) num = num - (repeats*max_num) #print repeats, num if repeats == 0: final_alpha = '%s' % alpha[num] else: final_alpha = '%s%s%s' % (sep, repeats, alpha[num]) return final_alpha def AlphaToNum(self, let): sep = '|' alpha = string.ascii_letters max_num = len(string.ascii_letters) - 1 if '|' not in let: if len(let) == 1: return alpha.find(let) else: return False if not let.startswith('|'): return False #letter = let[-1] #number = let[1:-1] if not let[-1].isalpha(): return False if not let[1:-1].isdigit(): return False #print 'max_num', int(let[1:-1])*max_num #print 'let',let[1:-1], alpha.find(let[1:-1]) return (int(let[1:-1])*max_num) + (alpha.find(let[-1])) def IsSignatureValid(self, sig): l_pos = sig.find('l') if l_pos == -1: return False sig_len = sig[:l_pos] if not sig_len.isdigit(): return False else: sig_len = int(sig_len) sig_core = sig[l_pos+1:] if len(sig_core) != sig_len: return False else: return True def GetCurrentOrderString(self): final_string = '' for mission in self.played: final_string += '%s\n' % self.missions[mission]['name'] return final_string def ContainsAlpha(self, current): for char in current: if char.isalpha(): return True return False def ConvertSignature(self, sig): if not self.IsSignatureValid(sig): return False sig_core = sig[sig.find('l')+1:] split_sig = [] current = '' for char in sig_core: if char.isalpha() and current != '': if current[-1].isalpha() or current[0].isalpha(): split_sig.append(current) current = '' if self.ContainsAlpha(current): split_sig.append(current) current = '' if char == '|': if current != '': split_sig.append(current) current = '' current += char split_sig.append(current) #return split_sig order_digits = [] for num in split_sig: print num if num[-1].isdigit(): char = num[-1] i = -1 while char.isdigit(): i -= 1 char = num[i] i+=1 #print num[i:] <--repeats #print num[:i] <--value for rep in range(0, int(num[i:])+1): order_digits.append(self.AlphaToNum(num[:i])) else: order_digits.append(self.AlphaToNum(num)) return order_digits def RunSignature(self, sig): if sig == '0l': return False order = self.ConvertSignature(sig) for order_num in order: self.ChooseNextMission(order_num) def LoadPath(self, sig): if sig == '0l': return False self.path_to_walk = self.ConvertSignature(sig) self.walk_length = len(self.path_to_walk) self.walking_path = True def TakeStep(self): if not self.walking_path: error_exit('OrderGen: TakeStep called when not walking path') if len(self.path_to_walk) == 0: error_exit('OrderGen: TakeStep called when no steps left to take') self.ChooseNextMission(self.path_to_walk.pop(0)) if len(self.path_to_walk) == 0: self.walking_path = False return True def PathProgress(self): ## print len(self.path_to_walk), self.walk_length ## print (1.0 * len(self.path_to_walk) / self.walk_length) return 100 - (1.0*len(self.path_to_walk) / self.walk_length) * 100 def GetCategories(self): cats = [] for item in self.missions: if 'category' in item: if item['category'] not in cats: cats.append(item['category']) return cats def CountCategory(self, category): done = 0 todo = 0 total = 0 #for a little bit of error checking for item in self.missions: if 'category' in item: if item['category'] == category: total += 1 if item.gid in self.played: done += 1 elif item.gid in self.remaining: todo += 1 ## print 'done',done ## print 'todo',todo ## print 'calc',done+todo ## print 'total',total return [done, total] def CountCategories(self): counts = {} for item in self.missions: if 'category' in item: if item['category'] not in counts: counts[item['category']] = [0,0,0] counts[item['category']][1] += 1 if item.gid in self.played: counts[item['category']][0] += 1 elif item.gid in self.remaining: counts[item['category']][2] += 1 return counts def GetOrderRange(self, object_id): if not self.use_flow: return [0, len(self.played)] earliest = 0 if object_id in self.needs: needs_ids = self.needs[object_id] for need in needs_ids: need_pos = self.played.index(need) if need_pos+1> earliest: earliest = need_pos + 1 latest = len(self.played) - 1 if 'unlocks' in self.missions[object_id]: for unlock in self.missions[object_id]['unlocks']: if unlock not in self.played: continue if self.played.index(unlock)- 1 < latest: latest = self.played.index(unlock) - 1 return [earliest, latest] def GetIVxex(gid): if 'xex' not in gid: error_exit('GetIVxex() called on non-xbox game id') if 'skip_get_xex' in gid: logging('%s requested skip GetIVxex()' % gid.gid) return True logging('GetIVxex called on %s' % gid.gid) build_dir = os.path.dirname(gid['xex']) xex_dir = settings['defaults']['iv_xex'] files = directory_list(xex_dir) full_paths = [] for fname in files: full_paths.append(os.path.join(xex_dir, fname)) FancyCopyFiles(full_paths, build_dir, overwrite=True, title='Copy XEX files') def RARfile(files, rardest): rarpath = settings['defaults']['rar'] if not os.path.exists(rarpath): error_exit('RARfile: path to rar.exe is not valid, please check the' ' value of "rar" in settings.ini, and that you have winrar ' 'installed.') #create file list textfile in temp flist_path = os.path.join(os.getenv('temp'),'flist.txt') flist = open(flist_path, 'w') for path in files: if os.path.exists(path): flist.write('%s\n' % path) else: logging('RARfile: File not found: "%s", skipping.' % path) flist.close() #command is 'rar a rardest @flist' args = ' a "%s" @"%s"' % (rardest, flist_path) rarproc = subprocess.Popen(rarpath+args) rarproc.wait() def FindPS3Dumps(sources): dump_paths = [] for source in sources: for fname in os.listdir(source): if fname.startswith('ps3core'): dump_paths.append(os.path.join(source, fname)) return dump_paths def SetPS3Home(gid): if 'set_home' in gid: homedir = gid['set_home'] else: error_exit('SetPS3Home called on a gid with no "set_home" setting') ps3run = os.path.join(os.path.join(os.getenv('SN_PS3_PATH'),'bin'), 'ps3run.exe') ps3run = '"'+ps3run+'"' os.system(ps3run+' -f '+homedir) os.system(ps3run+' -h '+homedir) def OneWeekChoice(evt_type): items = [] if evt_type == 'place_order': help_text = 'Place order for %s%s' elif evt_type == 'view_orders': help_text = 'View orders for %s%s' for i in range(0, 6): o_time_s = time.time() + i * (24*60*60) o_time = time.localtime(o_time_s) date_str = time.strftime('%A %d', o_time) items.append(['%s%s' % (date_str, GetNumberSuffix(int(date_str[-1]))), evt_type, o_time_s, help_text % (date_str, GetNumberSuffix(int(date_str[-1])))]) return MenuMaker('Select Order Date', items) def GetNumberSuffix(num): if num == 0: return 'th' elif num == 1: return 'st' elif num == 2: return 'nd' elif num == 3: return 'rd' elif num > 3 and num < 10: return 'th' else: return '' def CheckOrderLock(o_time_s): o_time = time.localtime(o_time_s) orderlock_path = os.path.join(settings['defaults']['food_folder'], time.strftime('%Y-%m-%d', o_time)) if os.path.exists(os.path.join(orderlock_path, 'order_lock.txt')): return True else: return False def WriteOrder(order, o_time_s=None): dest = settings['defaults']['food_folder'] fname = '%s.txt' % os.environ.get('username') if o_time_s == None: o_time = time.localtime() else: o_time = time.localtime(o_time_s) final_dest = os.path.join(dest, time.strftime('%Y-%m-%d', o_time)) if not os.path.exists(final_dest): os.makedirs(final_dest) out_file = open(os.path.join(final_dest, fname), 'w') out_file.write(order) out_file.close() in_file = open(os.path.join(final_dest, fname), 'r') print '\nOrder written to network:' for line in in_file: print line in_file.close() def TakeOrder(o_time_s=None): os.system('cls') if o_time_s == None: o_time = time.localtime() o_time_s = time.time() else: o_time = time.localtime(o_time_s) dest = settings['defaults']['food_folder'] dest_folder = os.path.join(dest, time.strftime('%Y-%m-%d', o_time)) final_dest = os.path.join(dest_folder, '%s.txt' % os.environ.get('username')) if os.path.exists(os.path.join(dest_folder, 'order_lock.txt')): print box_text('Ordering for this date has been locked, ' 'please contact a lead to submit your order.\n\n' 'Press any key to continue') wait_for_key() return False print 'Food-O-Tron 9000' print '================\n' if os.path.exists(final_dest): print 'You have already made an order for %s! It was:\n' % ( time.strftime('%Y-%m-%d', o_time)) infile = open(final_dest, 'r') for line in infile: print line infile.close() print print 'Enter your new order, or press enter to leave your order unchanged.' else: print 'Enter your order for %s%s.' % ( time.strftime('%A %d', o_time), GetNumberSuffix(int(time.strftime('%A %d', o_time)[-1]))) print order = raw_input('ORDER: ') if os.path.exists(final_dest) and order == '': print '\nOrder update cancelled, press any key to return.' wait_for_key() return True elif order == '': print '\nNothing entered, press any key to return.' wait_for_key() return True else: WriteOrder(order.replace('\n',''), o_time_s) print '\nPress any key to return.' wait_for_key() return True def ViewOrders(o_time_s = None): if o_time_s == None: o_time = time.localtime() o_time_s = time.time() else: o_time = time.localtime(o_time_s) folder = os.path.join( settings['defaults']['food_folder'], time.strftime('%Y-%m-%d', o_time)) items = [] items.append(['No', 'final_event', 'no', 'Do not lock ordering']) items.append(['Yes', 'final_event', 'yes', 'Lock ordering! No more orders will be allowed']) lock_sel = MiniMenu('Lock Ordering?', items, True) if lock_sel == 'yes': try: lock_file = open(os.path.join(folder, 'order_lock.txt'), 'w') lock_file.write(os.environ.get('username')) lock_file.close() except IOError: error_exit('Lock file could not be written') print 'Compiling order list for %s' % time.strftime('%Y-%m-%d', o_time) order_files = directory_list(folder,'*.txt') orders = {} for fname in order_files: name = os.path.basename(fname).replace('.txt','').lower() if name == 'order_lock': continue infile = open(fname, 'r') order_string = '' for line in infile: order_string += line.replace('\n','') infile.close() orders[name] = order_string print orders print 'Order list compiled, %s orders taken' % len(orders) print 'Generating orders.csv' outfname = os.path.join(os.environ.get('temp'),'orders.csv') outfile = open(outfname, 'w') outfile.write('Orders for:,%s\n' % time.strftime('%Y-%m-%d', o_time)) outfile.write('Number of orders:,%s\n' % len(orders)) ## for name, order in orders.iteritems(): ## outfile.write('"%s","%s"\n' % (name, order)) names = orders.keys() names.sort() for name in names: outfile.write('"%s","%s"\n' % (name, orders[name])) outfile.close() time.sleep(0.5) os.startfile(outfname) def SubstDrive(command): os.system('subst %s' % command) def WriteSwitches(fname, switches, separator): out = open(fname, 'w') for switch in switches: out.write('%s%s' % (switch, separator)) def GetCommandLineSeparator(gametype): seps = {'lan': ' ', 'rdr': '\n', 'gta_v': '\n'} try: return seps[gametype.lower()] except KeyError: logging('GetCommandLineSeparator(): KeyError: %s' % gametype.lower()) return '' def run_batfile(path): os.system('"%s"' % path) def ColdRebootXbox(): xdk_vars() os.system('xbReboot.exe /C') #=============================================================================== def TestLoad(): game_versions.LoadFile('game_versions.ini') settings.LoadFile('settings.ini') settings.LoadFile('variables.ini') settings.LoadFile(settings['defaults']['cab_hashes']) game_versions.DoStringReplacement(settings['variables']) DynamicProgramFiles(settings) log_path = os.path.join(sys.path[0],'qa_menu.log') game_versions = SettingsLoader() settings = SettingsLoader()