def compile_src(creator_name: str, src_dir: str, build_dir: str, mods_dir: str, mod_name: str = "Untitled") -> None: """ Packages your mod into a proper mod file. It creates 2 mod files, a full mod file which contains all the files in the source folder unchanged along with the compiled python versions next to uncompiled ones and a slim mod-file which contains only the compiled versions. Modified from andrew's code. https://sims4studio.com/thread/15145/started-python-scripting :param creator_name: The creators name :param src_dir: Source dir for the mod files :param build_dir: Place to put the mod files :param mods_dir: Place to an extra copy of the slim mod file for testing :param mod_name: Name to call the mod :return: Nothing """ # Prepend creator name to mod name mod_name = creator_name + '_' + mod_name mods_sub_dir = os.path.join(mods_dir, mod_name) # Create ts4script paths ts4script_full_build_path = os.path.join(build_dir, mod_name + '.ts4script') ts4script_mod_path = os.path.join(mods_sub_dir, mod_name + '.ts4script') print("Clearing out old builds...") # Delete and re-create build and sub-folder in Mods is_devmode = symlink_exists_win("", mods_dir, mod_name) symlink_remove_win("", mods_dir, mod_name) if is_devmode: print("Exiting Dev Mode...") remove_dir(build_dir) ensure_path_created(build_dir) ensure_path_created(mods_sub_dir) print("Re-building mod...") # Compile the mod zf = PyZipFile(ts4script_full_build_path, mode='w', compression=ZIP_STORED, allowZip64=True, optimize=2) compile_full(src_dir, zf) zf.close() # Copy it over to the mods folder shutil.copyfile(ts4script_full_build_path, ts4script_mod_path) print("----------") print("Complete")
def debug_install_mod(mod_src: str, mods_dir: str, mod_name: str, mod_folder_name: str) -> None: """ Compiles and installs the mod which adds a cheat code so the user can setup the debugger in-game :param mod_src: Path to the script which does this :param mods_dir: Path to the users mod folder :param mod_name: Name of the mod :param mod_folder_name: Name of mod Subfolder :return: Nothing """ print("Compiling and installing the cheatcode mod...") # Get destination file path mods_sub_dir = os.path.join(mods_dir, mod_folder_name) mod_path = os.path.join(mods_sub_dir, mod_name + '.ts4script') ensure_path_created(mods_sub_dir) # Get compiled path and compile mod mod_src_pyc = replace_extension(mod_src, "pyc") py_compile.compile(mod_src, mod_src_pyc) # Create mod at destination and add compiled file to it zf = PyZipFile(mod_path, mode='w', compression=ZIP_STORED, allowZip64=True, optimize=2) zf.write(mod_src_pyc, mod_name + ".pyc") zf.close()
def symlink_create_win(creator_name: str, src_dir: str, mods_dir: str, mod_name: str = "Untitled") -> None: """ Creates a symlink, it first wipes out the mod that may be there. When entering devmode, you don't compile anymore, so any compiled code needs to be removed. :param creator_name: Creator Name :param src_dir: Path to the source folder in this project :param mods_dir: Path to the Mods Folder :param mod_name: Name of Mod :return: Nothing """ # Build paths scripts_path = get_scripts_path(creator_name, mods_dir, mod_name) mod_folder_path = str(Path(scripts_path).parent) # Safely remove folder with symlink symlink_remove_win(creator_name, mods_dir, mod_name) # Re-create folder ensure_path_created(mod_folder_path) # Create Scripts Folder as a Directory Junction exec_cmd("mklink", '/J ' + '"' + scripts_path + '" ' '"' + src_dir + '"') print("") print( "Dev Mode is activated, you no longer have to compile after each change, run devmode.reload [path.of.module]" ) print( "to reload individual files while the game is running. To exit dev mode, simply run 'compile.py' which will" ) print("return things to normal.") print( "It's recomended to test a compiled version before final release after working in Dev Mode" ) print("")
from Utility.helpers_decompile import decompile_pre, decompile_zips, decompile_print_totals from Utility.helpers_path import ensure_path_created, remove_dir from settings import gameplay_folder_data, gameplay_folder_game, projects_python_path if os.path.exists(projects_python_path): print("This will wipe out the old decompilation at: " + projects_python_path) answer = input("Are you sure you want to do this? [y/n]: ") if answer is not "y": sys.exit("Program aborted by user") print("Emptying prior decompilation...") remove_dir(projects_python_path) # Make sure the python folder exists ensure_path_created(projects_python_path) # Do a pre-setup decompile_pre() # Decompile all zips to the python projects folder print("") print("Beginning decompilation") print("THIS WILL SERIOUSLY TAKE A VERY LONG TIME!!! " + "Additionally many files will not decompile properly which is normal.") print("") decompile_zips(gameplay_folder_data, projects_python_path) decompile_zips(gameplay_folder_game, projects_python_path) # Print final statistics
def decompile_dir(src_dir: str, dest_dir: str, filename: str) -> None: """ Decompiles a directory of compiled python files to a different directory Modified from andrew's code. https://sims4studio.com/thread/15145/started-python-scripting :param src_dir: Path of dir to decompile :param dest_dir: Path of dir to send decompiled files to :param filename: Original filename of what's being decompiled (For progress output purposes) :return: Nothing """ # Gain R/W to global counts and timing global total_suc_count global total_fail_count global total_count global total_minutes # Begin clock time_start = get_time() print("Decompiling " + filename) # Local counts for this one task col_count = 0 suc_count = 0 fail_count = 0 count = 0 # Go through each compiled python file in the folder for root, dirs, files in os.walk(src_dir): for filename in fnmatch.filter(files, python_compiled_ext): # Get details about the source file src_file_path = str(os.path.join(root, filename)) src_file_rel_path = get_rel_path(src_file_path, src_dir) # Create destination file path dest_file_path = replace_extension(dest_dir + os.path.sep + src_file_rel_path, "py") # And ensures the folders exist so there's no error # Make sure to strip off the file name at the end ensure_path_created(str(Path(dest_file_path).parent)) # Decompile it to destination success = exec_package("uncompyle6", "-o " + '"' + dest_file_path + '"' + " " + '"' + src_file_path + '"') # Print progress # Prints a single dot on the same line which gives a nice clean progress report # Tally number of files and successful / failed files if success: print(".", end="") suc_count += 1 total_suc_count += 1 else: print("x", end="") fail_count += 1 total_fail_count += 1 count += 1 total_count += 1 # Insert a new progress line every 80 characters col_count += 1 if col_count >= 80: col_count = 0 print("") time_end = get_time() elapsed_minutes = get_minutes(time_end, time_start) total_minutes += elapsed_minutes # Print a newline and then a compact completion message giving successful, failed, and total count stats and timing print("") print("") print("Completed") print("S: " + str(suc_count) + " [" + str(round((suc_count/count) * 100, 2)) + "%], ", end="") print("F: " + str(fail_count) + " [" + str(round((fail_count/count) * 100, 2)) + "%], ", end="") print("T: " + str(count) + ", ", end="") print(get_time_str(elapsed_minutes)) print("")
# distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This installs, updates, and removes package files in the projects folder to match the assets folder import fnmatch import os import shutil from settings import assets_path, mods_folder, creator_name, project_name, build_path from Utility.helpers_path import ensure_path_created, remove_file mod_name_folder_path = mods_folder + os.sep + creator_name + "_" + project_name ensure_path_created(mod_name_folder_path) file_list_failed = [] def remove_tl_packages(path: str) -> int: count = 0 # Remove existing package files for root, dirs, files in os.walk(path): for filename in fnmatch.filter(files, "*.package"): remove_file(root + os.sep + filename) count += 1 # Only cover the top-level folder break return count
def debug_install_egg(egg_path: str, mods_dir, dest_name: str, mod_folder_name: str) -> None: """ Copies the debug egg provided by Pycharm Pro which adds the capability to make debugging happen inside of PyCharm Pro. A bit of work goes into this so it'll be much slower. :param egg_path: Path to the debug egg :param mods_dir: Path to the mods folder :param dest_name: Name of the mod :param mod_folder_name: Name of mod Subfolder :return: """ print("Re-packaging and installing the debugging capability mod...") # Get egg filename and path filename = Path(egg_path).name mods_sub_dir = os.path.join(mods_dir, mod_folder_name) mod_path = os.path.join(mods_sub_dir, dest_name + ".ts4script") ensure_path_created(mods_sub_dir) # Get python ctypes folder sys_ctypes_folder = os.path.join(get_sys_folder(), "Lib", "ctypes") # Create temp directory tmp_dir = tempfile.TemporaryDirectory() tmp_egg = tmp_dir.name + os.sep + filename # Remove old mod in mods folder there, if it exists remove_file(mod_path) # Copy egg to temp path shutil.copyfile(egg_path, tmp_egg) # Extract egg # This step is a bit redundant but I need to copy over everything but one folder into the zip file and I don't # know how to do that in python so I copy over the zip, extract it, copy in the whole folder, delete the one # sub-folder, then re-zip everything up. It's a pain but it's what I know hwo to do now and Google's not much help zip = PyZipFile(tmp_egg) zip.extractall(tmp_dir.name) zip.close() # Remove archive remove_file(tmp_egg) # Copy ctype folder to extracted archive shutil.copytree(sys_ctypes_folder, tmp_dir.name + os.sep + "ctypes") # Remove that one folder remove_dir(tmp_dir.name + os.sep + "ctypes" + os.sep + "__pycache__") # Grab a handle on the egg zf = PyZipFile(mod_path, mode='w', compression=ZIP_STORED, allowZip64=True, optimize=2) # Add all the files in the tmp directory to the zip file for folder, subs, files in os.walk(tmp_dir.name): for file in files: archive_path = get_rel_path(folder + os.sep + file, tmp_dir.name) zf.write(folder + os.sep + file, archive_path) zf.close() # There's a temporary directory bug that causes auto-cleanup to sometimes fail # We're preventing crash messages from flooding the screen to keep things tidy try: tmp_dir.cleanup() except: pass