From 132d9a74f23899f611b22820f68fba29a40447b4 Mon Sep 17 00:00:00 2001 From: Dunestorm Date: Thu, 27 Aug 2020 18:22:19 +0100 Subject: [PATCH] MESwitcher (Python) v0.9 - Fully functional Python implementation of original PowerShell script. - Renamed PowerShell script. --- .../.vscode/.ropeproject/config.py | 114 ++++++++++++++++++ ME_Game_Toggler/.vscode/.ropeproject/objectdb | Bin 0 -> 222 bytes ME_Game_Toggler/.vscode/launch.json | 15 +++ ...Modded Game Toggler.ps1 => MESwitcher.ps1} | 2 +- ME_Game_Toggler/MESwitcher.py | 98 +++++++++++++++ ME_Game_Toggler/Run.bat | 3 + ME_Game_Toggler/_Modded_Game_Active | 0 7 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 ME_Game_Toggler/.vscode/.ropeproject/config.py create mode 100644 ME_Game_Toggler/.vscode/.ropeproject/objectdb create mode 100644 ME_Game_Toggler/.vscode/launch.json rename ME_Game_Toggler/{ME3 Vanilla-Modded Game Toggler.ps1 => MESwitcher.ps1} (98%) create mode 100644 ME_Game_Toggler/MESwitcher.py create mode 100644 ME_Game_Toggler/Run.bat create mode 100644 ME_Game_Toggler/_Modded_Game_Active diff --git a/ME_Game_Toggler/.vscode/.ropeproject/config.py b/ME_Game_Toggler/.vscode/.ropeproject/config.py new file mode 100644 index 0000000..dee2d1a --- /dev/null +++ b/ME_Game_Toggler/.vscode/.ropeproject/config.py @@ -0,0 +1,114 @@ +# The default ``config.py`` +# flake8: noqa + + +def set_prefs(prefs): + """This function is called before opening the project""" + + # Specify which files and folders to ignore in the project. + # Changes to ignored resources are not added to the history and + # VCSs. Also they are not returned in `Project.get_files()`. + # Note that ``?`` and ``*`` match all characters but slashes. + # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc' + # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc' + # '.svn': matches 'pkg/.svn' and all of its children + # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o' + # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o' + prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', + '.hg', '.svn', '_svn', '.git', '.tox'] + + # Specifies which files should be considered python files. It is + # useful when you have scripts inside your project. Only files + # ending with ``.py`` are considered to be python files by + # default. + # prefs['python_files'] = ['*.py'] + + # Custom source folders: By default rope searches the project + # for finding source folders (folders that should be searched + # for finding modules). You can add paths to that list. Note + # that rope guesses project source folders correctly most of the + # time; use this if you have any problems. + # The folders should be relative to project root and use '/' for + # separating folders regardless of the platform rope is running on. + # 'src/my_source_folder' for instance. + # prefs.add('source_folders', 'src') + + # You can extend python path for looking up modules + # prefs.add('python_path', '~/python/') + + # Should rope save object information or not. + prefs['save_objectdb'] = True + prefs['compress_objectdb'] = False + + # If `True`, rope analyzes each module when it is being saved. + prefs['automatic_soa'] = True + # The depth of calls to follow in static object analysis + prefs['soa_followed_calls'] = 0 + + # If `False` when running modules or unit tests "dynamic object + # analysis" is turned off. This makes them much faster. + prefs['perform_doa'] = True + + # Rope can check the validity of its object DB when running. + prefs['validate_objectdb'] = True + + # How many undos to hold? + prefs['max_history_items'] = 32 + + # Shows whether to save history across sessions. + prefs['save_history'] = True + prefs['compress_history'] = False + + # Set the number spaces used for indenting. According to + # :PEP:`8`, it is best to use 4 spaces. Since most of rope's + # unit-tests use 4 spaces it is more reliable, too. + prefs['indent_size'] = 4 + + # Builtin and c-extension modules that are allowed to be imported + # and inspected by rope. + prefs['extension_modules'] = [] + + # Add all standard c-extensions to extension_modules list. + prefs['import_dynload_stdmods'] = True + + # If `True` modules with syntax errors are considered to be empty. + # The default value is `False`; When `False` syntax errors raise + # `rope.base.exceptions.ModuleSyntaxError` exception. + prefs['ignore_syntax_errors'] = False + + # If `True`, rope ignores unresolvable imports. Otherwise, they + # appear in the importing namespace. + prefs['ignore_bad_imports'] = False + + # If `True`, rope will insert new module imports as + # `from import ` by default. + prefs['prefer_module_from_imports'] = False + + # If `True`, rope will transform a comma list of imports into + # multiple separate import statements when organizing + # imports. + prefs['split_imports'] = False + + # If `True`, rope will remove all top-level import statements and + # reinsert them at the top of the module when making changes. + prefs['pull_imports_to_top'] = True + + # If `True`, rope will sort imports alphabetically by module name instead + # of alphabetically by import statement, with from imports after normal + # imports. + prefs['sort_imports_alphabetically'] = False + + # Location of implementation of + # rope.base.oi.type_hinting.interfaces.ITypeHintingFactory In general + # case, you don't have to change this value, unless you're an rope expert. + # Change this value to inject you own implementations of interfaces + # listed in module rope.base.oi.type_hinting.providers.interfaces + # For example, you can add you own providers for Django Models, or disable + # the search type-hinting in a class hierarchy, etc. + prefs['type_hinting_factory'] = ( + 'rope.base.oi.type_hinting.factory.default_type_hinting_factory') + + +def project_opened(project): + """This function is called after opening the project""" + # Do whatever you like here! diff --git a/ME_Game_Toggler/.vscode/.ropeproject/objectdb b/ME_Game_Toggler/.vscode/.ropeproject/objectdb new file mode 100644 index 0000000000000000000000000000000000000000..fd35544095d00fc1ac3d607ca73d5901ddf3158c GIT binary patch literal 222 zcmXYpJ4*yH6otoqxa;`*8E%utLa-ATM6g(pg%oL$+2{l__vYr_QKlHsV*K3(u{wv3 z@0_pMNR@u9s_Nm+?Ad2F+a5d%=FZ%ww6$W*Gd4DwUB_&xiv931Cp$? zDh+fr(oEOokW&nD$l=4&yvdlna+bZqpgP}S9uBU4X$pRVSFCBV`KIMa$9h$!J-h>c u0<9)mPjqtq2VEbc1fW_kiz0oBo=)|mbU^TQHqm*z7P{b(E`R9CF{@t$MM#PO literal 0 HcmV?d00001 diff --git a/ME_Game_Toggler/.vscode/launch.json b/ME_Game_Toggler/.vscode/launch.json new file mode 100644 index 0000000..17e15f2 --- /dev/null +++ b/ME_Game_Toggler/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Current File", + "type": "python", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal" + } + ] +} \ No newline at end of file diff --git a/ME_Game_Toggler/ME3 Vanilla-Modded Game Toggler.ps1 b/ME_Game_Toggler/MESwitcher.ps1 similarity index 98% rename from ME_Game_Toggler/ME3 Vanilla-Modded Game Toggler.ps1 rename to ME_Game_Toggler/MESwitcher.ps1 index 3d37e58..c5ffb29 100644 --- a/ME_Game_Toggler/ME3 Vanilla-Modded Game Toggler.ps1 +++ b/ME_Game_Toggler/MESwitcher.ps1 @@ -4,7 +4,7 @@ $vanillaExt = ".vanilla" $modId = "_Modded_Game_Active" $modExt = ".mod" -$gamePath = "D:\Games\Origin\Mass Effect 3" +$gamePath = "R:\Games\Origin\Mass Effect 3" $configPath = $ENV:userprofile + "\Documents\Bioware\Mass Effect 3" #endregion Global Variables diff --git a/ME_Game_Toggler/MESwitcher.py b/ME_Game_Toggler/MESwitcher.py new file mode 100644 index 0000000..3104ef3 --- /dev/null +++ b/ME_Game_Toggler/MESwitcher.py @@ -0,0 +1,98 @@ +import os +import shutil +import enum +import psutil + +origin_library_path = "R:\\Games\\Origin\\" +config_path = "C:\\Users\\Dunestorm\\Documents\\BioWare\\" +me3_vanilla_dir = "Mass Effect 3.vanilla" +me3_mod_dir = "Mass Effect 3.mod" +me3_symlink_dir = "Mass Effect 3" + +print("Mass Effect 3 Switcher v0.9\n") + +class ActiveGame(enum.Enum): + Vanilla = 0 + Mod = 1 + +def CreateSymlink(root_path, symlink_rel_path, src_rel_path): + full_symlink_path = os.path.join(root_path, symlink_rel_path) + full_src_path = os.path.join(root_path, src_rel_path) + + if os.path.exists(full_symlink_path): + os.unlink(full_symlink_path) + os.symlink(full_src_path, full_symlink_path, True) + +def MigrateSaves(full_src_path, full_dst_path): + backup_ext = ".backup" + _full_backup_path = full_dst_path + backup_ext + + if os.path.exists(_full_backup_path): + shutil.rmtree(_full_backup_path) + shutil.copytree(full_dst_path, _full_backup_path, False) + + if os.path.exists(full_dst_path): + shutil.rmtree(full_dst_path) + shutil.copytree(full_src_path, full_dst_path, False) + +def IdentifyInstallation(path): + active_game = ActiveGame.Vanilla + + if os.path.exists(os.path.join(path, "cmm_vanilla")): + active_game = ActiveGame.Vanilla + else: + active_game = ActiveGame.Mod + + return active_game + +def IsExecutableBlocking(): + result = False + + while result == False: + for p in psutil.process_iter(): + if p.name() == "Origin.exe": + result = True + break + if p.name() == "MassEffect3.exe": + result = True + break + break + return result + +if IsExecutableBlocking(): + print("Please exit Origin and Mass Effect 3 before running this script!") + input("Press the enter key to exit...") + exit() + +if os.path.islink(os.path.join(origin_library_path, me3_symlink_dir)) == False: + CreateSymlink(origin_library_path, me3_symlink_dir, me3_vanilla_dir) + CreateSymlink(config_path, me3_symlink_dir, me3_vanilla_dir) + print("First time setup complete") + +active_game = IdentifyInstallation(os.path.join(origin_library_path, me3_symlink_dir)) + +user_selection = None +if active_game == ActiveGame.Mod: + user_selection = input("Modded game is currently active, would you like to switch to vanilla? [y/N]\n") +else: + user_selection = input("Vanilla game is currently active, would you like to switch to modded? [y/N]\n") + +if user_selection.lower() == "y": + if active_game == ActiveGame.Mod: + CreateSymlink(origin_library_path, me3_symlink_dir, me3_vanilla_dir) + CreateSymlink(config_path, me3_symlink_dir, me3_vanilla_dir) + print("Identified modded ME3 as active game, switched to vanilla") + + MigrateSaves(os.path.join(config_path, me3_mod_dir, "Save"), + os.path.join(config_path, me3_vanilla_dir, "Save")) + print("Save games have been migrated from modded ME3 to vanilla") + else: + CreateSymlink(origin_library_path, me3_symlink_dir, me3_mod_dir) + CreateSymlink(config_path, me3_symlink_dir, me3_mod_dir) + print("Identified vanilla ME3 as active game, switched to modded") + + MigrateSaves(os.path.join(config_path, me3_vanilla_dir, "Save"), + os.path.join(config_path, me3_mod_dir, "Save")) + print("Save games have been migrated from vanilla ME3 to modded") + +input("Press the enter key to exit...") \ No newline at end of file diff --git a/ME_Game_Toggler/Run.bat b/ME_Game_Toggler/Run.bat new file mode 100644 index 0000000..75d64ed --- /dev/null +++ b/ME_Game_Toggler/Run.bat @@ -0,0 +1,3 @@ +@echo off +cd /D "%~dp0" +python meswitcher.py \ No newline at end of file diff --git a/ME_Game_Toggler/_Modded_Game_Active b/ME_Game_Toggler/_Modded_Game_Active new file mode 100644 index 0000000..e69de29