def windows_to_steam_conversion(original_save_path: str) -> None: containers_list = Container.get_containers_list(original_save_path) Logger.logPrint('\nContainers found:' + str(containers_list)) container_name = Scenario.ask_for_containers_to_convert( containers_list) if len(containers_list) > 1 else containers_list[0] container_url = utils.join_paths(original_save_path, container_name) Logger.logPrint('\nInitializing Astroneer save container...') container = Container(container_url) Logger.logPrint(f'Detected chunks: {container.chunk_count}') Logger.logPrint('Container file loaded successfully !\n') saves_to_export = Scenario.ask_saves_to_export(container.save_list) Scenario.ask_rename_saves(saves_to_export, container.save_list) to_path = utils.join_paths(original_save_path, 'Steam saves') utils.make_dir_if_doesnt_exists(to_path) Logger.logPrint( f'\nExtracting saves {str([i+1 for i in saves_to_export])}') Logger.logPrint(f'Container: {container.full_path} Export to: {to_path}', "debug") for save_index in saves_to_export: save = container.save_list[save_index] Scenario.ask_overwrite_save_while_file_exists(save, to_path) Scenario.export_save_to_steam(save, original_save_path, to_path) Logger.logPrint(f"\nSave {save.name} has been exported succesfully.")
def ask_copy_target(folder_main_name: str): ''' Requests a target folder to the user TODO [doc] to explain the folder name format Arguments: folder_main_name: Returns ... ''' Logger.logPrint('Where would you like to copy your save folder ?') Logger.logPrint('\t1) New folder on my desktop') Logger.logPrint("\t2) New folder in a custom path") choice = input() while choice not in ('1', '2'): Logger.logPrint(f'\nPlease choose 1 or 2') choice = input() Logger.logPrint(f'copy_choice {choice}', 'debug') if choice == '1': # Winpath is needed here because Windows user can have a custom Desktop location save_path = utils.get_windows_desktop_path() elif choice == '2': Logger.logPrint(f'\nEnter your custom folder path:') save_path = input() Logger.logPrint(f'save_path {save_path}', 'debug') return utils.join_paths(save_path, utils.create_folder_name(folder_main_name))
def parse_path(plugin_name, plugin_path): """ Transforms the plugin path (along with the plugin name) into an absolute URL, taking into account the location of the plugin folders. """ try: plugin_path = join_paths([[ConfParser.plugins_path], plugin_name, plugin_path]) except Exception as e: print "[WARNING] Exception parsing settings from section 'paths'. Details: %s" % str(e) return plugin_path
def get_data_set_from_path(path): abs_file_path = utils.join_paths(path) points_array = [] with open(abs_file_path, "r") as f: whole_line_wo_whitespaces = [line.rstrip() for line in f] for line in whole_line_wo_whitespaces: array_of_x_label_y = line.split(" ") points_array.append( handle_any_number_of_spaces(array_of_x_label_y)) return (points_array)
def parse_path(plugin_name, plugin_path): """ Transforms the plugin path (along with the plugin name) into an absolute URL, taking into account the location of the plugin folders. """ try: plugin_path = join_paths([[ConfParser.plugins_path], plugin_name, plugin_path]) except Exception as e: print "[WARNING] Exception parsing settings from section 'paths'. Details: %s" % str(e) return plugin_path
def ask_overwrite_if_file_exists(filename: str, target: str) -> bool: file_url = utils.join_paths(target, filename) if utils.is_path_exists(file_url): do_overwrite = None while do_overwrite not in ('y', 'n'): Logger.logPrint( f'\nFile {filename} already exists, overwrite it ? (y/n)') do_overwrite = input().lower() return do_overwrite == 'y' else: return True
def process_net(model, swa_model, model_immutable, train_iter, valid_iter, test_iter, optimizer, criterion, swa_epochs, pretrain_epochs, cpt_filename, swa_lr_set = [0.001, 0.05, 0.1], cycle_length_set = [1, 5, 10], device = 'cpu'): print('Training') with open(utils.join_paths(csv_directory, cpt_filename + "-" + date + '.csv'), 'w', newline='') as csv_file: writer = csv.writer(csv_file) writer.writerow(columns) train(model, train_iter, valid_iter, optimizer, criterion, pretrain_epochs, device, writer, cpt_filename) model_immutable.load_state_dict(copy.deepcopy(model.state_dict())) csv_file.close() print('SWA Training') for swa_lr in swa_lr_set: print('LEARNING RATE-{:2.4f}'.format(swa_lr)) for cycle_length in cycle_length_set: with open(utils.join_paths(csv_directory, '{}-SWA-{:03}-{}-{}.csv'.format(cpt_filename, swa_lr, cycle_length, date)), 'w', newline='') as csv_file: writer = csv.writer(csv_file) writer.writerow(columns) print('CYCLE LENGTH-{:03}'.format(cycle_length)) model.load_state_dict(copy.deepcopy(model_immutable.state_dict())) swa_train(model, swa_model, train_iter, valid_iter, optimizer, criterion, pretrain_epochs, swa_epochs, swa_lr, cycle_length, device, writer, cpt_filename) test(model, swa_model, test_iter, criterion, device, writer)
def get_save_folders_from_path(path) -> list: microsoft_save_folders = [] for root, _, files in os.walk(path): for file in files: if re.search(r'^container\.', file): container_full_path = utils.join_paths(root, file) Logger.logPrint(f'Container file found:{container_full_path}', 'debug') container_text = read_container_text_from_path(container_full_path) if do_container_text_match_date(container_text): Logger.logPrint(f'Matching save folder {root}', 'debug') microsoft_save_folders.append(root) return microsoft_save_folders
class ConfParser(): from localsettings import SRC_DIR # Note: surround inside list whenever treated as a unit plugins_path = join_paths([SRC_DIR, "python", "plugins"]) @staticmethod def parse_config(plugin_name, path="./settings.conf"): """ Reads and parses every setting defined in the 'settings.conf' within the plugin that goes under the name 'plugin_name'. """ ConfParser.plugin_name = plugin_name settings = {} try: confparser = ConfigParser.RawConfigParser() confparser.readfp(open(path)) for section in confparser.sections(): settings[section] = {} for (key, val) in confparser.items(section): # Any Python structure inside a string is to be converted into the desired structure settings[section][key] = ast.literal_eval(val) # Postprocessing: complete content folders with each plugin absolute path (keeps a copy previously) if section == "paths": settings[section]["relative__%s" % key] = settings[section][key] settings[section][key] = ConfParser.parse_path( plugin_name, settings[section][key]) except Exception as e: print "[WARNING] Exception parsing configuration file '%s'. Details: %s" % ( str(path), str(e)) return settings @staticmethod def parse_path(plugin_name, plugin_path): """ Transforms the plugin path (along with the plugin name) into an absolute URL, taking into account the location of the plugin folders. """ try: plugin_path = join_paths([[ConfParser.plugins_path], plugin_name, plugin_path]) except Exception as e: print "[WARNING] Exception parsing settings from section 'paths'. Details: %s" % str( e) return plugin_path
def convert_to_steam(self, source) -> BytesIO: """Exports a save to the disk in its Steam file format The save is returned in a buffer representing a unique file obtained by concatenating all its chunks Arguments: source: Where to read the chunks of the save Returns: A buffer containing the Steam save """ buffer = BytesIO() for chunk_name in self.chunks_names: chunk_file_path = join_paths(source, chunk_name) with open(chunk_file_path, 'rb') as chunk_file: buffer.write(chunk_file.read()) return buffer
def get_containers_list(path) -> list: """ List all containers in a folder Arguments: path -- path for search containers Returns: Returns a list of all containers found (only filename of container) Exception: None """ folder_content = list_folder_content(path) containers_list = [ file for file in folder_content if AstroSaveContainer.is_a_container_file(join_paths(path, file)) ] if not containers_list or len(containers_list) == 0: raise FileNotFoundError return containers_list
def ask_copy_target(): Logger.logPrint('Where would you like to copy your save folder ?') Logger.logPrint('\t1) New folder on my desktop') Logger.logPrint("\t2) New folder in a custom path") choice = input() while choice not in ('1', '2'): Logger.logPrint(f'\nPlease choose 1 or 2') choice = input() Logger.logPrint(f'copy_choice {choice}', 'debug') if choice == '1': # Winpath is needed here because Windows user can have a custom Desktop location save_path = utils.get_windows_desktop_path() elif choice == '2': Logger.logPrint(f'\nEnter your custom folder path:') save_path = input() Logger.logPrint(f'save_path {save_path}', 'debug') return utils.join_paths(save_path, utils.create_folder_name('AstroSaveFolder'))
def steam_to_windows_conversion(original_save_path: str) -> None: Logger.logPrint('\n\n/!\\ WARNING /!\\') Logger.logPrint( '/!\\ Astroneer needs to be closed longer than 20 seconds before we can start exporting your saves /!\\' ) Logger.logPrint( '/!\\ More info and save restoring procedure are available on Github (cf. README) /!\\' ) loading_bar = LoadingBar(15) loading_bar.start_loading() xbox_astroneer_save_folder = Scenario.backup_win_before_steam_export() steamsave_files_list = AstroSave.get_steamsaves_list(original_save_path) saves_list = AstroSave.init_saves_list_from(steamsave_files_list) original_saves_name = [] for save in saves_list: original_saves_name.append(save.name) saves_indexes_to_export = Scenario.ask_saves_to_export(saves_list) Scenario.ask_rename_saves(saves_indexes_to_export, saves_list) Logger.logPrint( f'\nExtracting saves {str([i+1 for i in saves_indexes_to_export])}') Logger.logPrint( f'Working folder: {original_save_path} Export to: {xbox_astroneer_save_folder}', "debug") for save_index in saves_indexes_to_export: save = saves_list[save_index] original_save_full_path = utils.join_paths( original_save_path, original_saves_name[save_index] + '.savegame') Scenario.export_save_to_xbox(save, original_save_full_path, xbox_astroneer_save_folder) Logger.logPrint(f"\nSave {save.name} has been exported succesfully.")
def get_steamsaves_list(path) -> list: """List all Steam saves in a folder Arguments: path -- path where to search for Steam saves Returns: Returns a list of all Steam saves found (only filenames) Exception: None """ folder_content = list_folder_content(path) steamsaves_list = [ file for file in folder_content if AstroSave.is_a_steamsave_file(join_paths(path, file)) ] if not steamsaves_list or len(steamsaves_list) == 0: raise FileNotFoundError return steamsaves_list
def export_save_to_steam(save: AstroSave, from_path: str, to_path: str) -> None: target_full_path = utils.join_paths(to_path, save.get_file_name()) converted_save = save.convert_to_steam(from_path) utils.write_buffer_to_file(target_full_path, converted_save)
def export_save(save, from_path, to_path): target_full_path = utils.join_paths(to_path, save.get_file_name()) converted_save = save.convert_to_steam(from_path) utils.write_buffer_to_file(target_full_path, converted_save)
class PluginLoader(): # Allows only one instance of this class __metaclass__ = Singleton plugin_settings = {} from settings import SRC_DIR # Note: surround inside list whenever treated as a unit plugins_path = join_paths([SRC_DIR, "python", "plugins"]) @staticmethod def generate_static_content_urls(media_url=""): """ Crafts URLs for static content (img, css, js) inside plugins. Note: content inside plugin is expected to follow the same structure as in settings.MEDIA_URL (e.g. '/static/media/default'). The generated URLs will have the associated name X_media_Y, where X = {"img","css","js"} and Y = (plugin name) """ from django.conf.urls.defaults import patterns, url urlpatterns = [] # 'plugins_path' already setted before but just checking # for format since that is very important default_plugins_path = PluginLoader.plugins_path if default_plugins_path[0] == "/": default_plugins_path = default_plugins_path[1:] if default_plugins_path[-1] == "/": default_plugins_path = default_plugins_path[:-1] for plugin in PluginLoader.plugin_settings: for url_type in ["img", "css", "js"]: content_route = PluginLoader.plugin_settings.get(plugin).get( "paths").get("relative__%s_dirs" % url_type) urlpatterns += patterns( '', # url(r'^%s%s/%s/(?P<path>.*)$' % (str(plugin), media_url, url_type), url( r'^%s%s/%s/(?P<path>.*)$' % (str(plugin), media_url, content_route), 'django.views.static.serve', # {'document_root': "/%s%s%s/%s" % (PluginLoader.plugins_path, str(plugin), media_url, url_type)}, name="%s_media_%s" % (url_type, str(plugin))) { 'document_root': "/%s/%s/%s" % (default_plugins_path, str(plugin), content_route) }, name="%s_media_%s" % (url_type, str(plugin)))) return urlpatterns @staticmethod def load_settings(path=None): """ Entry point for the load of settings. If settings were not already defined, load these. """ try: pl = PluginLoader() # If settings were already loaded, do not attempt again if not pl.plugin_settings: if not path: path = pl.plugins_path else: pl.set_plugins_path(path) PluginLoader.plugin_settings = pl.load_settings_from_folder( path) except Exception as e: print "[WARNING] There may be some problem with the plugin configuration files. Exception: %s" % str( e) return PluginLoader.plugin_settings def load_settings_from_folder(self, plugins_path="."): """ Iterates over the folders inside the plugins path and loads each one's settings in a big dictionary that follows the structure: { 'plugin_name': { 'section_name': { 'attribute_name': 'attribute_value', ... }, ... }, ... } """ try: for plugin_name in os.listdir(plugins_path): if os.path.isdir(os.path.join(plugins_path, plugin_name)): try: plugin_path = os.path.join(plugins_path, plugin_name) plugin_data = self.load_settings_from_plugin( plugin_path) if plugin_data: self.plugin_settings[plugin_name] = plugin_data except: pass except: pass return self.plugin_settings def load_settings_from_plugin(self, path="./"): """ Read the plugin's configuration file into a dictionary where each section of the config is a sub-dictionary that contains some properties. """ plugin_name = "" # Remove last slash to parse data if path[-1] == "/": path = path[:-1] plugin_name = path.split("/")[-1] path = path + "/settings.conf" return ConfParser.parse_config(plugin_name, path) @staticmethod def set_plugins_path(plugins_path): """ Sets the folder where plugins are contained. """ PluginLoader.plugins_path = plugins_path
def export_save_to_xbox(save: AstroSave, from_file: str, to_path: str) -> None: chunk_uuids, converted_chunks = save.convert_to_xbox(from_file) chunk_count = len(chunk_uuids) if chunk_count >= 10: Logger.logPrint( f'The selected save contains {chunk_count} which is over the 9 chunks limit AstroSaveconverter can handle yet' ) Logger.logPrint( f'Congrats for having such a huge save, please open an issue on the GitHub :D' ) for i in range(chunk_count): # The file name is the HEX upper form of the uuid chunk_name = save.chunks_names[i] Logger.logPrint(f'UUID as file name: {chunk_name}', "debug") target_full_path = utils.join_paths(to_path, chunk_name) Logger.logPrint(f'Chunk file written to: {target_full_path}', "debug") # Regenerating chunk name if it already exists. Very, very unlikely while utils.is_path_exists(target_full_path): Logger.logPrint(f'UUID: {chunk_name} already exists ! (omg)', "debug") chunk_uuids[i] = save.regenerate_uuid(i) chunk_name = save.chunks_names[i] Logger.logPrint(f'Regenerated UUID: {chunk_name}', "debug") target_full_path = utils.join_paths(to_path, chunk_name) # TODO [enhance] raise exception if can't write, catch it then delete all the chunks already written and exit utils.write_buffer_to_file(target_full_path, converted_chunks[i]) # Container is updated only after all the chunks of the save have been written successfully container_file_name = Container.get_containers_list(to_path)[0] container_full_path = utils.join_paths(to_path, container_file_name) with open(container_full_path, "r+b") as container: container.read(4) current_container_chunk_count = int.from_bytes(container.read(4), byteorder='little') new_container_chunk_count = current_container_chunk_count + chunk_count container.seek(-4, 1) container.write( new_container_chunk_count.to_bytes(4, byteorder='little')) chunks_buffer = BytesIO() for i in range(chunk_count): total_written_len = 0 encoded_save_name = save.name.encode('utf-16le', errors='ignore') total_written_len += chunks_buffer.write(encoded_save_name) if chunk_count > 1: # Multi-chunks save. Adding metadata, format: '$${i}${chunk_count}$1' chunk_metadata = f'$${i}${chunk_count}$1' encoded_metadata = chunk_metadata.encode('utf-16le', errors='ignore') total_written_len += chunks_buffer.write(encoded_metadata) chunks_buffer.write(b"\00" * (144 - total_written_len)) chunks_buffer.write(chunk_uuids[i].bytes_le) Logger.logPrint(f'Editing container: {container_full_path}', "debug") utils.append_buffer_to_file(container_full_path, chunks_buffer)
def main(): # user input if not g_args.type: g_args.type = utils.read_string_input(msg="type", init_value=DEFAULT_TEMPLATE) if not g_args.output: g_args.output = utils.read_path_input(msg="file path") g_args.author = utils.read_string_input(msg="author", init_value=g_args.author) if not g_args.description: g_args.description = utils.read_string_input( msg="description", init_value=HEADER_DESCRIPTION) g_args.description = format_description(g_args.description) if g_args.type != "bash": g_args.copy_utils = utils.confirm("Copy utilities?", "y" if g_args.copy_utils else "n") template_path = utils.join_paths_str(g_args.script_dir, TEMPLATE_OPTIONS[g_args.type]) if utils.exists_dir(g_args.output): print(f"Error: target path is a directory!") sys.exit(0) elif utils.exists_file(g_args.output): if not utils.confirm_delete_file(g_args.output, "n"): utils.exit("Aborted") out_folder = utils.get_file_path(g_args.output) out_file = utils.get_file_name(g_args.output) if not utils.exists_dir(out_folder): utils.make_dir(g_args.output) # copy template utils.copy_to(template_path, g_args.output) print(f"Created file {g_args.output}") if g_args.type == "class": utils.replace_file_text(g_args.output, CLASS_NAME, out_file) if g_args.type != "bash": if g_args.copy_utils: utils_folder = PY_UTILS_DIR out_py_utils_dir = utils.join_paths(out_folder, utils_folder) utils.make_dir(out_py_utils_dir) utils.copy_to(PY_UTILS_FILE, out_py_utils_dir) print(f"Created file {out_py_utils_dir}/{PY_UTILS_FILE}") else: print(""" Important: Please make sure that python utils are available, i.e. inside PYTHONPATH. Clone repository via: git clone https://github.com/amplejoe/py_utils.git """) # header information date = utils.get_date_str() utils.replace_file_text(g_args.output, HEADER_DATE, date) utils.replace_file_text(g_args.output, HEADER_AUTHOR, g_args.author) if g_args.description: utils.replace_file_text(g_args.output, HEADER_DESCRIPTION, g_args.description)