From 29c2bab0f94b682cf8e3c801fa6a1c802fd0cfe2 Mon Sep 17 00:00:00 2001 From: Zedb0T <89345505+Zedb0T@users.noreply.github.com> Date: Tue, 15 Aug 2023 22:46:29 -0400 Subject: [PATCH 01/25] Update launcherUtils.py --- utils/launcherUtils.py | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index d8f3d41..36ca001 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -439,9 +439,10 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE): try_kill_process("gk.exe") try_kill_process("goalc.exe") print("Done update starting extractor This one can take a few moments! \n") - extractor_command_list = [InstallDir + "\extractor.exe", "-f", iso_path] + + #extract and compile, but dont boot the game so we can move the iso files + extractor_command_list = [InstallDir + "\extractor.exe", "-f", iso_path , "-e", "-v", "-d", "-c"] print(extractor_command_list) - subprocess.Popen(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir)) # move the extrated contents to the universal launchers directory for next time. @@ -449,12 +450,33 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE): while process_exists("extractor.exe"): print("extractor.exe still running, sleeping for 1s") time.sleep(1) - if not (exists((UniversalIsoPath + r"\jak1\Z6TAIL.DUP"))): - # os.makedirs(AppdataPATH + "\OpenGOAL-Launcher\data\iso_data") - print("The new directory is created!") - shutil.move(InstallDir + "/data/iso_data", "" + UniversalIsoPath + "") - # try_remove_dir(InstallDir + "/data/iso_data") - # os.symlink("" + UniversalIsoPath +"", InstallDir + "/data/iso_data") + + #cleanup and remove a corrupted iso + if os.path.exists(UniversalIsoPath + r"\iso_data") and os.path.isdir(UniversalIsoPath + r"\iso_data"): + print("Removing corrupted iso destination...") + shutil.rmtree(UniversalIsoPath + r"\iso_data") + print("corrupt iso removed.") + + #should be good to move iso now + shutil.move(InstallDir + "/data/iso_data", UniversalIsoPath + r"\iso_data") + + #keep checking to make sure the move is in a finished state + while not (exists((UniversalIsoPath + r"\jak1\Z6TAIL.DUP"))): + time.sleep(1) + + if(NotExtracted): + print("Error! Iso data does not appear to be extracted to " + UniversalIsoPath +r"\jak1\Z6TAIL.DUP") + print("Will ask user to provide ISO") + if(NotCompiled): + print("Error! The game is not compiled") + if((LastWrite < LatestRel)): + print("Looks like we need to download a new update!") + print(LastWrite) + print(LatestRel) + print("Is newest posted update older than what we have installed? " + str((LastWrite < LatestRel))) + + #ok launch game :D + subprocess.Popen(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir)) else: # if we dont need to update, then close any open instances of the game and just launch it From 3e7cdce17368a9057eeca9ea1e8f9734825f4907 Mon Sep 17 00:00:00 2001 From: Zedb0T <89345505+Zedb0T@users.noreply.github.com> Date: Tue, 15 Aug 2023 23:55:19 -0400 Subject: [PATCH 02/25] More cleanup --- utils/launcherUtils.py | 44 +++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index 36ca001..1bad5d9 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -126,7 +126,8 @@ def launch_local(MOD_ID): time.sleep(1) InstallDir = ModFolderPATH + MOD_ID - UniversalIsoPath = AppdataPATH + "\OpenGOAL\jak1\mods\data\iso_data\iso_data" + UniversalIsoPath = AppdataPATH + "\OpenGOAL\jak1\mods\data\iso_data" + GKCOMMANDLINElist = [ os.path.abspath(InstallDir + "\gk.exe"), # Using os.path.abspath to get the absolute path. "--proj-path", @@ -149,7 +150,8 @@ def openFolder(path): def reinstall(MOD_ID): InstallDir = ModFolderPATH + MOD_ID AppdataPATH = os.getenv("APPDATA") - UniversalIsoPath = AppdataPATH + "\OpenGOAL\jak1\mods\data\iso_data\iso_data" + UniversalIsoPath = AppdataPATH + "\OpenGOAL\jak1\mods\data\iso_data" + GKCOMMANDLINElist = [ InstallDir + "\gk.exe", "--proj-path", @@ -162,6 +164,7 @@ def reinstall(MOD_ID): # if ISO_DATA has content, store this path to pass to the extractor if exists(UniversalIsoPath + r"\jak1\Z6TAIL.DUP"): iso_path = UniversalIsoPath + "\jak1" + else: # if ISO_DATA is empty, prompt for their ISO and store its path. root = tk.Tk() @@ -206,9 +209,11 @@ def reinstall(MOD_ID): # move the extrated contents to the universal launchers directory for next time. if not (exists((UniversalIsoPath + r"\jak1\Z6TAIL.DUP"))): + # os.makedirs(AppdataPATH + "\OpenGOAL-Launcher\data\iso_data") print("The new directory is created!") shutil.move(InstallDir + "/data/iso_data", "" + UniversalIsoPath + "") + # try_remove_dir(InstallDir + "/data/iso_data") # os.symlink("" + UniversalIsoPath +"", InstallDir + "/data/iso_data") @@ -251,7 +256,8 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE): # paths InstallDir = ModFolderPATH + MOD_ID AppdataPATH = os.getenv("APPDATA") - UniversalIsoPath = AppdataPATH + "\OpenGOAL\jak1\mods\data\iso_data\iso_data" + UniversalIsoPath = AppdataPATH + "\OpenGOAL\jak1\mods\data\iso_data" + GKCOMMANDLINElist = [ InstallDir + "\gk.exe", "--proj-path", @@ -295,6 +301,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE): # update checks NotExtracted = bool(not (exists(UniversalIsoPath + r"\jak1\Z6TAIL.DUP"))) + NotCompiled = bool(not (exists(InstallDir + r"\data\out\jak1\fr3\GAME.fr3"))) needUpdate = bool((LastWrite < LatestRel) or (NotExtracted) or NotCompiled) @@ -376,18 +383,24 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE): #if ISO_DATA has content, store this path to pass to the extractor if (exists(UniversalIsoPath +r"\jak1\Z6TAIL.DUP")): + print("We found ISO data from a previous mod installation! Lets use it!") print("Found in " + UniversalIsoPath +r"\jak1\Z6TAIL.DUP") iso_path = UniversalIsoPath + "\jak1" else: #if ISO_DATA is empty, prompt for their ISO and store its path. print("Looking for some ISO data in " + UniversalIsoPath + "\\jak1\\") + print("We did not find ISO data from a previous mod, lets ask for some!") + # prompt for ISO file root = tk.Tk() - print("Please select your iso.") root.title("Select ISO") root.geometry("230x1") - iso_path = filedialog.askopenfilename() + + top_level = tk.Toplevel(root) + top_level.attributes("-topmost", True) # Set the file dialog to stay on top + + iso_path = filedialog.askopenfilename(parent=top_level) root.destroy() if pathlib.Path(iso_path).is_file: if not (pathlib.Path(iso_path).suffix).lower() == ".iso": @@ -422,16 +435,6 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE): "/pc-settings.gc", r"/" + MOD_ID + "-settings.gc", ) - replaceText( - InstallDir + r"\data\goal_src\jak1\pc\pckernel-common.gc", - "/pc-settings.gc", - r"/" + MOD_ID + "-settings.gc", - ) - replaceText( - InstallDir + r"\data\goal_src\jak1\pc\pckernel-common.gc", - "/pc-settings.gc", - r"/" + MOD_ID + "-settings.gc", - ) # if extractOnUpdate is True, check their ISO_DATA folder @@ -452,13 +455,14 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE): time.sleep(1) #cleanup and remove a corrupted iso - if os.path.exists(UniversalIsoPath + r"\iso_data") and os.path.isdir(UniversalIsoPath + r"\iso_data"): - print("Removing corrupted iso destination...") - shutil.rmtree(UniversalIsoPath + r"\iso_data") - print("corrupt iso removed.") + if os.path.exists(UniversalIsoPath ) and os.path.isdir(UniversalIsoPath ): + print("Removing corrupted iso destination...") + shutil.rmtree(UniversalIsoPath + "/jak1") + print("corrupt iso removed.") #should be good to move iso now - shutil.move(InstallDir + "/data/iso_data", UniversalIsoPath + r"\iso_data") + shutil.move(InstallDir + "/data/iso_data/jak1", UniversalIsoPath ) + print("copying " + InstallDir + "/data/iso_data" + "to " + UniversalIsoPath ) #keep checking to make sure the move is in a finished state while not (exists((UniversalIsoPath + r"\jak1\Z6TAIL.DUP"))): From 57de08bb003c763fafce1eeaf7921cda9c415495 Mon Sep 17 00:00:00 2001 From: Zedb0T <89345505+Zedb0T@users.noreply.github.com> Date: Wed, 16 Aug 2023 19:04:42 -0400 Subject: [PATCH 03/25] add base jak 2 support --- buildlaunchercoreEXE.bat | 8 +- openGOALModLauncher.py | 30 +- openGOALModLauncher.spec | 49 +++ requirements.txt | 1 + resources/jak1_mods.json | 116 +++++--- utils/launcherUtils.py | 252 +++++++++++++--- utils/launcherUtilsbackup.py | 557 +++++++++++++++++++++++++++++++++++ 7 files changed, 924 insertions(+), 89 deletions(-) create mode 100644 openGOALModLauncher.spec create mode 100644 utils/launcherUtilsbackup.py diff --git a/buildlaunchercoreEXE.bat b/buildlaunchercoreEXE.bat index b5f5df3..817b7dc 100644 --- a/buildlaunchercoreEXE.bat +++ b/buildlaunchercoreEXE.bat @@ -1,8 +1,8 @@ set mypath=%~dp0 -pyinstaller --onefile openGOALModLauncher.py --icon resources\appicon.ico +pyinstaller --onefile openGOALModLauncher.py --icon resources\appicon.ico --collect-data "pycdlib" --hidden-import=pycdlib datas=[(path.join(site_packages,"pycdlib")], move "%mypath%dist\openGOALModLauncher.exe" "%mypath%/" RENAME "%mypath%\openGOALModLauncher.exe" "openGOALModLauncher.exe" -@RD /S /Q "%mypath%/build" -@RD /S /Q "%mypath%/dist" -DEL /S /Q "%mypath%/openGOALModLauncher.spec" +REM @RD /S /Q "%mypath%/build" +REM @RD /S /Q "%mypath%/dist" +REM DEL /S /Q "%mypath%/openGOALModLauncher.spec" diff --git a/openGOALModLauncher.py b/openGOALModLauncher.py index 843f1a7..7ea3c5f 100644 --- a/openGOALModLauncher.py +++ b/openGOALModLauncher.py @@ -21,10 +21,16 @@ import webbrowser import os from os.path import exists -import urllib.request import shutil import tkinter from appdirs import AppDirs +from appdirs import AppDirs +import platform +import stat + +from pathlib import Path + + sg.theme("DarkBlue3") @@ -203,11 +209,12 @@ def exitWithError(): INCLUDE_UNINSTALLED = True LATEST_TABLE_SORT = [6, False] # wakeup sorted by last launch date - +mod_game = "jak2" def getRefreshedTableData(sort_col_idx): # uncomment/comment the next two lines if you want to test with a local file - mod_dict = requests.get("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/jak1_mods.json").json() - # mod_dict = json.loads(open("resources/jak1_mods.json", "r").read()) + # mod_dict = requests.get("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/jak1_mods.json").json() + mod_dict = json.loads(open("resources/jak1_mods.json", "r").read()) + mod_dict = dict(sorted(mod_dict.items(), key=lambda x: x[1]["release_date"], reverse=True)) mod_table_data = [] @@ -216,8 +223,10 @@ def getRefreshedTableData(sort_col_idx): } for mod_id in mod_dict: + mod = mod_dict[mod_id] mod_name = mod["name"] + mod["install_date"] = "Not Installed" mod["access_date"] = "Not Installed" @@ -242,7 +251,7 @@ def getRefreshedTableData(sort_col_idx): mod["contributors"] = ", ".join(mod["contributors"]) mod["tags"].sort() mod["tags"] = ", ".join(mod["tags"]) - + # determine latest available update datetime - disabled as too easy to get rate-limited by github (can we do in bulk maybe?) # mod["latest_available_update_date"] = "1900-01-01 00:00" # update_date = githubUtils.getLatestAvailableUpdateDatetime(mod["URL"]) @@ -275,9 +284,9 @@ def getRefreshedTableData(sort_col_idx): (mod["videos_url"] if "videos_url" in mod else ""), (mod["photos_url"] if "photos_url" in mod else ""), (mod["image_override_url"] if "image_override_url" in mod else ""), + (mod["game"] if "game" in mod else "") ] ) - if sort_col_idx is None: # not from a heading click, retain sorting remapped_col_idx = LATEST_TABLE_SORT[0] @@ -417,11 +426,10 @@ def getRefreshedTableData(sort_col_idx): ] window = sg.Window("OpenGOAL Mod Launcher", layout, icon=iconfile, finalize=True) - def handleModTableSelection(row): global LATEST_TABLE_DATA mod = LATEST_TABLE_DATA[row] - # print(mod) + print(mod) mod_id = mod[0] mod_name = mod[1] @@ -435,6 +443,8 @@ def handleModTableSelection(row): mod_videos_url = mod[9] mod_photos_url = mod[10] mod_image_override_url = mod[11] + mod_game = mod[12] + # update text and metadata window["-LAUNCH-"].update( @@ -444,6 +454,7 @@ def handleModTableSelection(row): window["-SELECTEDMODNAME-"].metadata["id"] = mod_id window["-SELECTEDMODNAME-"].metadata["url"] = mod_url window["-SELECTEDMODNAME-"].metadata["image_override_url"] = mod_image_override_url + window["-SELECTEDMODNAME-"].metadata["game"] = mod_game window["-SELECTEDMODDESC-"].update(mod_desc) window["-SELECTEDMODTAGS-"].update(f"Tags: {mod_tags}") window["-SELECTEDMODCONTRIBUTORS-"].update(f"Contributors: {mod_contributors}") @@ -551,12 +562,13 @@ def reset(): tmpModName = window["-SELECTEDMODNAME-"].get() tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] tmpModURL = window["-SELECTEDMODNAME-"].metadata["url"] + tmpGame = window["-SELECTEDMODNAME-"].metadata["game"] # online launch window["-LAUNCH-"].update(disabled=True) window["-LAUNCH-"].update("Updating...") [linkType, tmpModURL] = githubUtils.identifyLinkType(tmpModURL) - launcherUtils.launch(tmpModURL, tmpModSelected, tmpModName, linkType) + launcherUtils.launch(tmpModURL, tmpModSelected, tmpModName, linkType, tmpGame) # refresh table in case new mod installed reset() diff --git a/openGOALModLauncher.spec b/openGOALModLauncher.spec new file mode 100644 index 0000000..53a7925 --- /dev/null +++ b/openGOALModLauncher.spec @@ -0,0 +1,49 @@ +# -*- mode: python ; coding: utf-8 -*- +from PyInstaller.utils.hooks import collect_data_files + +datas = [] +datas += collect_data_files('pycdlib') + + +block_cipher = None + + +a = Analysis( + ['openGOALModLauncher.py'], + pathex=[], + binaries=[], + datas=datas, + hiddenimports=['pycdlib'], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False, +) +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + [], + name='openGOALModLauncher', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, + icon='resources\\appicon.ico', +) diff --git a/requirements.txt b/requirements.txt index f0ae9ba..76bb57b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,4 @@ Pillow progressbar cloudscraper appdirs +pycdlib diff --git a/resources/jak1_mods.json b/resources/jak1_mods.json index cc10541..5f179aa 100644 --- a/resources/jak1_mods.json +++ b/resources/jak1_mods.json @@ -15,7 +15,8 @@ "release_date": "2022-08-28", "URL": "https://github.com/OpenGOAL-Unofficial-Mods/opengoal-randomizer-mod-pack/tree/main", "website_url": "https://github.com/OpenGOAL-Unofficial-Mods/opengoal-randomizer-mod-pack", - "videos_url": "https://www.youtube.com/watch?v=B5mEhVt0v68" + "videos_url": "https://www.youtube.com/watch?v=B5mEhVt0v68", + "game": "jak1" }, "random_actor_scale": { "name": "Fricked up", @@ -31,7 +32,8 @@ ], "release_date": "2023-01-19", "URL": "https://github.com/OpenGOAL-Unofficial-Mods/opengoal-mod-base/tree/fucked", - "website_url": "https://github.com/OpenGOAL-Unofficial-Mods/opengoal-mod-base" + "website_url": "https://github.com/OpenGOAL-Unofficial-Mods/opengoal-mod-base", + "game": "jak1" }, "local_multi": { "name": "Shared Screen Multiplayer! (beta) ", @@ -49,7 +51,8 @@ "release_date": "2022-09-05", "URL": "https://github.com/OpenGOAL-Unofficial-Mods/opengoal-multiplayer-rando-mod-pack/tree/main", "website_url": "https://github.com/OpenGOAL-Unofficial-Mods/opengoal-multiplayer-rando-mod-pack/blob/main/README.md#opengoal-multiplayer--randomizer-mod-pack", - "videos_url": "https://www.youtube.com/watch?v=BeVl4x6gjC0" + "videos_url": "https://www.youtube.com/watch?v=BeVl4x6gjC0", + "game": "jak1" }, "random_cell_order": { "name": "Random Cell Order", @@ -66,7 +69,8 @@ ], "release_date": "2023-02-02", "URL": "https://github.com/OpenGOAL-Unofficial-Mods/opengoal-rco", - "website_url": "https://github.com/OpenGOAL-Unofficial-Mods/opengoal-rco/blob/main/README.md" + "website_url": "https://github.com/OpenGOAL-Unofficial-Mods/opengoal-rco/blob/main/README.md", + "game": "jak1" }, "speedrun_practice": { "name": "Speedrun practice mod", @@ -82,7 +86,8 @@ "release_date": "2022-10-23", "URL": "https://github.com/OpenGOAL-Unofficial-Mods/Jakspeedrunningpractice", "website_url": "https://github.com/OpenGOAL-Unofficial-Mods/Jakspeedrunningpractice/blob/main/README.md#jak-speedrunning-practice-opengoal", - "videos_url": "https://www.youtube.com/watch?v=a_SIccmgpj4" + "videos_url": "https://www.youtube.com/watch?v=a_SIccmgpj4", + "game": "jak1" }, "microtransactions": { "name": "MicroTransactions", @@ -97,7 +102,8 @@ "release_date": "2022-08-28", "URL": "https://github.com/himham-jak/Jak1-but-Microtransactions/releases", "website_url": "https://github.com/himham-jak/Jak1-but-Microtransactions/blob/microtransactions/README.md", - "videos_url": "https://www.youtube.com/watch?v=q5TZ9U399J8" + "videos_url": "https://www.youtube.com/watch?v=q5TZ9U399J8", + "game": "jak1" }, "jak_go_fast": { "name": "Jak1 but every power cell he gets faster", @@ -110,7 +116,8 @@ "challenge" ], "release_date": "2022-08-30", - "URL": "https://github.com/himham-jak/Jak-1-Movement-Mod/releases" + "URL": "https://github.com/himham-jak/Jak-1-Movement-Mod/releases", + "game":"jak1" }, "first_person": { "name": "First Person Mode", @@ -125,7 +132,8 @@ "release_date": "2022-09-30", "URL": "https://github.com/OpenGOAL-Unofficial-Mods/First-person-jak", "website_url": "https://github.com/OpenGOAL-Unofficial-Mods/First-person-jak", - "videos_url": "https://www.youtube.com/watch?v=2RhxWSSaNlM" + "videos_url": "https://www.youtube.com/watch?v=2RhxWSSaNlM", + "game": "jak1" }, "classic_plus": { "name": "Classic+", @@ -138,7 +146,8 @@ ], "release_date": "2022-08-30", "URL": "https://github.com/Zedb0T/Zed-Mods/tree/Classic+-Release", - "website_url": "https://github.com/Zedb0T/Zed-Mods/tree/Classic+-Release" + "website_url": "https://github.com/Zedb0T/Zed-Mods/tree/Classic+-Release", + "game": "jak1" }, "flutflut_legacy": { "name": "The FlutFlut Legacy", @@ -154,7 +163,8 @@ "release_date": "2022-09-10", "URL": "https://github.com/OpenGOAL-Mods/OG-FlutFlut-Legacy/releases", "website_url": "https://github.com/Zedb0T/TheFlutFlutLegacy", - "videos_url": "https://www.youtube.com/watch?v=_z8GhVWFYfI" + "videos_url": "https://www.youtube.com/watch?v=_z8GhVWFYfI", + "game": "jak1" }, "ice_everywhere": { "name": "Ice Everywhere", @@ -168,7 +178,8 @@ ], "release_date": "2022-08-28", "URL": "https://github.com/Zedb0T/iceverywhere/releases", - "website_url": "https://github.com/Zedb0T/iceverywhere" + "website_url": "https://github.com/Zedb0T/iceverywhere", + "game": "jak1" }, "orb_hunt": { "name": "Orb Hunt", @@ -183,7 +194,8 @@ "release_date": "2023-01-05", "URL": "https://github.com/dallmeyer/opengoal-orbhunt", "website_url": "https://github.com/dallmeyer/opengoal-orbhunt/blob/main/README.md#opengoal---the-precursor-orb-hunt", - "videos_url": "https://www.youtube.com/playlist?list=PLcFimep6cyLekygymgefmPqusnFYETuyb" + "videos_url": "https://www.youtube.com/playlist?list=PLcFimep6cyLekygymgefmPqusnFYETuyb", + "game": "jak1" }, "super_mario_64": { "name": "The SM64 Legacy", @@ -199,7 +211,8 @@ "release_date": "2022-10-28", "URL": "https://github.com/dallmeyer/opengoal-sm64", "website_url": "https://github.com/dallmeyer/opengoal-sm64/blob/main/README.md#opengoal-jak-1---super-mario-64-style", - "videos_url": "https://www.youtube.com/watch?v=xNpsAzsPBTQ" + "videos_url": "https://www.youtube.com/watch?v=xNpsAzsPBTQ", + "game": "jak1" }, "zoomer_legacy": { "name": "The Zoomer Legacy", @@ -215,7 +228,8 @@ "release_date": "2022-09-20", "URL": "https://github.com/dallmeyer/The-Zoomer-Legacy", "website_url": "https://github.com/dallmeyer/The-Zoomer-Legacy", - "videos_url": "https://www.youtube.com/watch?v=BDvvCY8gFDQ" + "videos_url": "https://www.youtube.com/watch?v=BDvvCY8gFDQ", + "game": "jak1" }, "inirdin_textures": { "name": "Texture Showcase", @@ -228,7 +242,8 @@ ], "release_date": "2022-08-31", "URL": "https://github.com/Inirdin/opengoal-inirdin-texture-showcase/tree/main", - "website_url": "https://github.com/Inirdin/opengoal-inirdin-texture-showcase/blob/main/README.md#opengoal-inirdin-texture-showcase" + "website_url": "https://github.com/Inirdin/opengoal-inirdin-texture-showcase/blob/main/README.md#opengoal-inirdin-texture-showcase", + "game": "jak1" }, "Ng_minus": { "name": "NG-", @@ -242,7 +257,8 @@ ], "release_date": "2023-04-16", "URL": "https://github.com/OpenGOAL-Unofficial-Mods/ng-", - "website_url": "https://github.com/OpenGOAL-Unofficial-Mods/ng-" + "website_url": "https://github.com/OpenGOAL-Unofficial-Mods/ng-", + "game": "jak1" }, "jak_grows": { "name": "Jak and Daxter But Every Time He Grabs An Orb He Grows", @@ -257,7 +273,8 @@ "release_date": "2022-11-01", "URL": "https://github.com/Xyphles/X-mod-base/tree/Jak-and-Daxter-But-Every-Time-He-Grabs-An-Orb-He-Grows", "website_url": "https://github.com/Xyphles/X-mod-base/tree/Jak-and-Daxter-But-Every-Time-He-Grabs-An-Orb-He-Grows", - "videos_url": "https://www.youtube.com/watch?v=dBP_25yT5YU" + "videos_url": "https://www.youtube.com/watch?v=dBP_25yT5YU", + "game": "jak1" }, "snowy_legacy": { "name": "Snowy Legacy", @@ -271,7 +288,8 @@ "release_date": "2022-09-08", "URL": "https://github.com/kekdeveloper/opengoal-mod-snowy-legacy/tree/main", "website_url": "https://github.com/kekdeveloper/opengoal-mod-snowy-legacy/blob/main/README.md#opengoal-mod-snowy-legacy", - "videos_url": "https://www.youtube.com/watch?v=djoAMJMre6U" + "videos_url": "https://www.youtube.com/watch?v=djoAMJMre6U", + "game": "jak1" }, "mystery_word": { "name": "Mystery Word V2", @@ -286,7 +304,8 @@ "release_date": "2022-11-03", "URL": "https://github.com/MortisDG/MysteryWordV2", "website_url": "https://github.com/MortisDG/MysteryWordV2", - "videos_url": "https://www.youtube.com/watch?v=dlXkd6FhjyY" + "videos_url": "https://www.youtube.com/watch?v=dlXkd6FhjyY", + "game": "jak1" }, "random_actors": { "name": "Random Actors/entities", @@ -302,7 +321,8 @@ ], "release_date": "2022-11-04", "URL": "https://github.com/Zedb0T/Zed-Mods/tree/Random-Actor-dev", - "website_url": "https://github.com/Zedb0T/Zed-Mods/tree/Random-Actor-dev" + "website_url": "https://github.com/Zedb0T/Zed-Mods/tree/Random-Actor-dev", + "game": "jak1" }, "mikeeee": { "name": "Random Enemies", @@ -318,7 +338,8 @@ ], "release_date": "2022-12-05", "URL": "https://github.com/Zedb0T/Zed-Mods/tree/Random-enemies", - "website_url": "https://github.com/Zedb0T/Zed-Mods/tree/Random-enemies" + "website_url": "https://github.com/Zedb0T/Zed-Mods/tree/Random-enemies", + "game": "jak1" }, "mirror_mode_every_cell": { "name": "Mirror mode every cell", @@ -333,7 +354,8 @@ ], "release_date": "2022-11-08", "URL": "https://github.com/Zedb0T/Zed-Mods/tree/mirrormodeeverycell-", - "website_url": "https://github.com/Zedb0T/Zed-Mods/tree/mirrormodeeverycell-" + "website_url": "https://github.com/Zedb0T/Zed-Mods/tree/mirrormodeeverycell-", + "game": "jak1" }, "new_eco": { "name": "New Eco type", @@ -347,7 +369,8 @@ ], "release_date": "2022-11-04", "URL": "https://github.com/OpenGOAL-Unofficial-Mods/New-Eco-types/tree/w-pink", - "website_url": "https://github.com/OpenGOAL-Unofficial-Mods/New-Eco-types/tree/w-pink" + "website_url": "https://github.com/OpenGOAL-Unofficial-Mods/New-Eco-types/tree/w-pink", + "game": "jak1" }, "open_ghosts": { "name": "OpenGhosts", @@ -361,7 +384,8 @@ ], "release_date": "2022-12-22", "URL": "https://github.com/dryice10/openghosts", - "website_url": "https://github.com/dryice10/openghosts/blob/main/README.md#openghosts" + "website_url": "https://github.com/dryice10/openghosts/blob/main/README.md#openghosts", + "game": "jak1" }, "forgotten_lands": { "name": "The Forgotten Lands", @@ -377,7 +401,8 @@ "release_date": "2023-01-08", "URL": "https://github.com/Kuitar5/the-forgotten-lands/releases", "website_url": "https://github.com/Kuitar5/the-forgotten-lands/blob/main/README.md#the-forgotten-lands", - "videos_url": "https://youtube.com/playlist?list=PLUvfXyvZk2SC0A8TtqYV8ap97aVGu9rRP" + "videos_url": "https://youtube.com/playlist?list=PLUvfXyvZk2SC0A8TtqYV8ap97aVGu9rRP", + "game": "jak1" }, "blindfold_assist": { "name": "Blindfold Assist Mod", @@ -391,7 +416,8 @@ ], "release_date": "2023-01-22", "URL": "https://github.com/OpenGOAL-Unofficial-Mods/blindfold-assist", - "website_url": "https://github.com/OpenGOAL-Unofficial-Mods/blindfold-assist/blob/main/README.md" + "website_url": "https://github.com/OpenGOAL-Unofficial-Mods/blindfold-assist/blob/main/README.md", + "game": "jak1" }, "its_ogre_now": { "name": "ShrekAdventures", @@ -407,7 +433,8 @@ "release_date": "2023-04-05", "URL": "https://github.com/Zedb0T/shrekadventures/releases", "website_url": "https://github.com/Zedb0T/shrekadventures", - "videos_url": "https://twitter.com/JakSpeedruns/status/1645693475277668354" + "videos_url": "https://twitter.com/JakSpeedruns/status/1645693475277668354", + "game": "jak1" }, "invisible_Legacy": { "name": "The Invisible Legacy", @@ -422,7 +449,8 @@ ], "release_date": "2023-07-05", "URL": "https://github.com/OpenGOAL-Mods/OG-Invisible-Legacy/releases", - "website_url": "https://github.com/OpenGOAL-Mods/OG-Invisible-Legacy" + "website_url": "https://github.com/OpenGOAL-Mods/OG-Invisible-Legacy", + "game": "jak1" }, "orange_demon": { "name": "Orange Demon Challenge", @@ -436,7 +464,8 @@ "release_date": "2023-07-09", "URL": "https://github.com/Hat-Kid/jak-project/releases", "image_override_url": "https://cdn.discordapp.com/attachments/1124072608548266105/1127708472394391653/orange-demon-thumb.png", - "website_url": "https://gist.github.com/Hat-Kid/ede85d11ecf98f89f1e857160cdf82c7" + "website_url": "https://gist.github.com/Hat-Kid/ede85d11ecf98f89f1e857160cdf82c7", + "game": "jak1" }, "wood_crate_break_alot": { "name": "Break wood creates!", @@ -450,7 +479,8 @@ "release_date": "2023-07-19", "URL": "https://github.com/OpenGOAL-Mods/OG-All-Wooden-Boxes/releases", "image_override_url": "https://media.discordapp.net/attachments/183621467659960321/1131419019543576626/image.png", - "website_url": "https://github.com/OpenGOAL-Mods/OG-All-Wooden-Boxes" + "website_url": "https://github.com/OpenGOAL-Mods/OG-All-Wooden-Boxes", + "game": "jak1" }, "casual_legacy": { "name": "Casual Legacy!", @@ -464,7 +494,8 @@ "release_date": "2023-07-29", "URL": "https://github.com/OpenGOAL-Mods/OG-Casual-Legacy/releases", "image_override_url": "https://s3.amazonaws.com/ebaumsworld.prod/uploads1608065784494-hed.jpg", - "website_url": "https://github.com/OpenGOAL-Mods/OG-Casual-Legacy" + "website_url": "https://github.com/OpenGOAL-Mods/OG-Casual-Legacy", + "game":"jak1" }, "super_jak_bros": { "name": "Super Jak bros!", @@ -478,7 +509,8 @@ "release_date": "2023-07-31", "URL": "https://github.com/Zed-Mod-School/OG-2D/releases", "image_override_url": "https://cdn.discordapp.com/attachments/994297625585139834/1135434268714213376/jakbros.png", - "website_url": "https://github.com/Zed-Mod-School/OG-2D" + "website_url": "https://github.com/Zed-Mod-School/OG-2D", + "game": "jak1" }, "up": { "name": "Jak Up", @@ -494,6 +526,24 @@ "release_date": "2023-08-10", "URL": "https://github.com/dallmeyer/jak-up/releases", "image_override_url": "https://cdn.discordapp.com/attachments/1007077732032721037/1139110276273287239/image.png", - "website_url": "https://github.com/dallmeyer/jak-up/blob/main/README.md" + "website_url": "https://github.com/dallmeyer/jak-up/blob/main/README.md", + "game": "jak1" + }, + "mod_base_2": { + "name": "Jak 2", + "desc": "Early test build. WARNING: the levels take up ~400MB, and will take a couple minutes to install.", + "contributors": ["barg034"], + "tags": [ + "beta", + "gameplay-mod", + "challenge", + "custom-level", + "speedrunning" + ], + "release_date": "2023-08-10", + "URL": "https://github.com/OpenGOAL-Mods/OG-Mod-Base/releases", + "image_override_url": "https://cdn.discordapp.com/attachments/1007077732032721037/1139110276273287239/image.png", + "website_url": "https://github.com/dallmeyer/jak-up/blob/main/README.md", + "game": "jak2" } } diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index 1bad5d9..d8351d6 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -23,7 +23,8 @@ from appdirs import AppDirs import platform import stat - +import pycdlib +from pathlib import Path EXTRACT_ON_UPDATE = "true" FILE_DATE_TO_CHECK = "gk.exe" @@ -117,7 +118,7 @@ def local_mod_image(MOD_ID): return None -def launch_local(MOD_ID): +def launch_local(MOD_ID, GAME): try: # Close Gk and goalc if they were open. try_kill_process("gk.exe") @@ -126,7 +127,7 @@ def launch_local(MOD_ID): time.sleep(1) InstallDir = ModFolderPATH + MOD_ID - UniversalIsoPath = AppdataPATH + "\OpenGOAL\jak1\mods\data\iso_data" + UniversalIsoPath = AppdataPATH + "\OpenGOAL\mods\data\iso_data" GKCOMMANDLINElist = [ os.path.abspath(InstallDir + "\gk.exe"), # Using os.path.abspath to get the absolute path. @@ -136,6 +137,19 @@ def launch_local(MOD_ID): "-fakeiso", "-v", ] + if (GAME == "jak2"): + GKCOMMANDLINElist = [ + InstallDir + "\gk.exe", + "--proj-path", + InstallDir + "\\data", + "-v", + "--game", + "jak2", + "--", + "-boot", + "-fakeiso", + "-debug", + ] print(GKCOMMANDLINElist) subprocess.Popen(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir)) except Exception as e: # Catch all exceptions and print the error message. @@ -150,7 +164,7 @@ def openFolder(path): def reinstall(MOD_ID): InstallDir = ModFolderPATH + MOD_ID AppdataPATH = os.getenv("APPDATA") - UniversalIsoPath = AppdataPATH + "\OpenGOAL\jak1\mods\data\iso_data" + UniversalIsoPath = AppdataPATH + "\OpenGOAL\mods\data\iso_data" GKCOMMANDLINElist = [ InstallDir + "\gk.exe", @@ -162,8 +176,8 @@ def reinstall(MOD_ID): ] # if ISO_DATA has content, store this path to pass to the extractor - if exists(UniversalIsoPath + r"\jak1\Z6TAIL.DUP"): - iso_path = UniversalIsoPath + "\jak1" + if exists(UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"): + iso_path = UniversalIsoPath + "\\" + GAME else: # if ISO_DATA is empty, prompt for their ISO and store its path. @@ -174,9 +188,11 @@ def reinstall(MOD_ID): iso_path = filedialog.askopenfilename() root.destroy() if pathlib.Path(iso_path).is_file: - if not (pathlib.Path(iso_path).suffix).lower() == ".iso": + if not (pathlib.Path(iso_path).suffix).lower() == ".iso" or not (pathlib.Path(iso_path).suffix).lower() == ".zip": 1 / 0 + + print("Extraction completed successfully.") # Close Gk and goalc if they were open. try_kill_process("gk.exe") try_kill_process("goalc.exe") @@ -208,7 +224,7 @@ def reinstall(MOD_ID): time.sleep(1) # move the extrated contents to the universal launchers directory for next time. - if not (exists((UniversalIsoPath + r"\jak1\Z6TAIL.DUP"))): + if not (exists((UniversalIsoPath + r"" + "//" + GAME + "//" + "Z6TAIL.DUP"))): # os.makedirs(AppdataPATH + "\OpenGOAL-Launcher\data\iso_data") print("The new directory is created!") @@ -237,8 +253,71 @@ def replaceText(path, search_text, replace_text): print(f"Text replaced successfully in file '{path}'.") +def ensure_dir(path): + path.mkdir(parents=True, exist_ok=True) + +def extract_recursive(iso, parent_iso_path, extract_dir_path): + for child in iso.list_children(iso_path=parent_iso_path): + identifier = child.file_identifier().decode() + absolute_iso_path = f'{parent_iso_path}{identifier}' + + # Skip . and .. directories + if identifier in ['.', '..']: + continue + + # Recurse directories or extract files + if child.is_dir(): + extract_recursive(iso, f'{absolute_iso_path}/', extract_dir_path / identifier) + else: + file_name = identifier.split(';')[0] + + # Strip empty file extensions (e.g. DMMY. -> DMMY) + if file_name.endswith('.'): + file_name = file_name[:-1] + + file_path = extract_dir_path / file_name + + # Ensure the parent directory exists + ensure_dir(extract_dir_path) + + # Write the output file + print(f' {absolute_iso_path}: ', end='', flush=True) + iso.get_file_from_iso(file_path, iso_path=f'{absolute_iso_path}') + print(f'DONE', flush=True) -def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE): +def extract_iso(ISO_PATH, EXTRACT_DIR): + # Clean original extraction directory + ISO_PATH = Path(ISO_PATH) + EXTRACT_DIR = Path(EXTRACT_DIR) + if EXTRACT_DIR.exists(): + shutil.rmtree(EXTRACT_DIR) + + # Create extraction directories + ensure_dir(EXTRACT_DIR) + + # Open the iso for reading + iso = pycdlib.PyCdlib() + iso.open(ISO_PATH) + + # Extract the contents of the iso + print('Extracting ISO contents', flush=True) + extract_recursive(iso, '/', EXTRACT_DIR) + + # Close the iso + iso.close() + return True + + +def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): + print(GAME) + print(GAME) + print(GAME) + print(GAME) + print(GAME) + print(GAME) + print(GAME) + print(GAME) + print(GAME) if URL is None: return @@ -256,7 +335,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE): # paths InstallDir = ModFolderPATH + MOD_ID AppdataPATH = os.getenv("APPDATA") - UniversalIsoPath = AppdataPATH + "\OpenGOAL\jak1\mods\data\iso_data" + UniversalIsoPath = AppdataPATH + "\OpenGOAL\mods\data\iso_data" GKCOMMANDLINElist = [ InstallDir + "\gk.exe", @@ -267,6 +346,20 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE): "-v", ] + if (GAME == "jak2"): + GKCOMMANDLINElist = [ + InstallDir + "\gk.exe", + "--proj-path", + InstallDir + "\\data", + "-v", + "--game", + "jak2", + "--", + "-boot", + "-fakeiso", + "-debug", + ] + # store Latest Release and check our local date too. if LINK_TYPE == githubUtils.LinkTypes.BRANCH: LatestRel = datetime.strptime( @@ -300,15 +393,15 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE): ) # update checks - NotExtracted = bool(not (exists(UniversalIsoPath + r"\jak1\Z6TAIL.DUP"))) - - NotCompiled = bool(not (exists(InstallDir + r"\data\out\jak1\fr3\GAME.fr3"))) + NotExtracted = bool(not (exists(UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"))) + + NotCompiled = bool(not (exists(InstallDir + r"\data\out" + "//" + GAME + "//" + "fr3\GAME.fr3"))) needUpdate = bool((LastWrite < LatestRel) or (NotExtracted) or NotCompiled) print("Currently installed version created on: " + LastWrite.strftime('%Y-%m-%d %H:%M:%S')) print("Newest version created on: " + LatestRel.strftime('%Y-%m-%d %H:%M:%S')) if(NotExtracted): - print("Error! Iso data does not appear to be extracted to " + UniversalIsoPath +r"\jak1\Z6TAIL.DUP") + print("Error! Iso data does not appear to be extracted to " + UniversalIsoPath +"//" + GAME + "//" + "Z6TAIL.DUP") print("Will ask user to provide ISO") if(NotCompiled): print("Error! The game is not compiled") @@ -319,17 +412,17 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE): print("Is newest posted update older than what we have installed? " + str((LastWrite < LatestRel))) # attempt to migrate any old settings files from using MOD_NAME to MOD_ID - if exists(AppdataPATH + "\OpenGOAL\jak1\settings\\" + MOD_NAME + "-settings.gc"): + if exists(AppdataPATH + "\OpenGOAL" + "//" + GAME + "//" + "settings\\" + MOD_NAME + "-settings.gc"): # just to be safe delete the migrated settings file if it already exists (shouldn't happen but prevents rename from failing below) - if exists(AppdataPATH + "\OpenGOAL\jak1\settings\\" + MOD_ID + "-settings.gc"): + if exists(AppdataPATH + "\OpenGOAL" + "//" + GAME + "//" + "settings\\" + MOD_ID + "-settings.gc"): os.remove( - AppdataPATH + "\OpenGOAL\jak1\settings\\" + MOD_ID + "-settings.gc" + AppdataPATH + "\OpenGOAL" + "//" + GAME + "//" + "settings\\" + MOD_ID + "-settings.gc" ) # rename settings file os.rename( - AppdataPATH + "\OpenGOAL\jak1\settings\\" + MOD_NAME + "-settings.gc", - AppdataPATH + "\OpenGOAL\jak1\settings\\" + MOD_ID + "-settings.gc", + AppdataPATH + "\OpenGOAL" + "//" + GAME + "//" + "settings\\" + MOD_NAME + "-settings.gc", + AppdataPATH + "\OpenGOAL" + "//" + GAME + "//" + "settings\\" + MOD_ID + "-settings.gc", ) # force update to ensure we recompile with adjusted settings filename in pckernel.gc @@ -382,14 +475,19 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE): try_remove_file(InstallDir + "/extractor.exe") #if ISO_DATA has content, store this path to pass to the extractor - if (exists(UniversalIsoPath +r"\jak1\Z6TAIL.DUP")): + if (exists(UniversalIsoPath +"//" + GAME + "//" + "Z6TAIL.DUP")): print("We found ISO data from a previous mod installation! Lets use it!") - print("Found in " + UniversalIsoPath +r"\jak1\Z6TAIL.DUP") - iso_path = UniversalIsoPath + "\jak1" + print("Found in " + UniversalIsoPath +"//" + GAME + "//" + "Z6TAIL.DUP") + iso_path = UniversalIsoPath + "\\" + GAME else: + #cleanup and remove a corrupted iso + if os.path.exists(UniversalIsoPath) and os.path.isdir(UniversalIsoPath) and not (exists((UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"))): + print("Removing corrupted iso destination...") + shutil.rmtree(UniversalIsoPath + "//" + GAME) + print("corrupt iso removed.") #if ISO_DATA is empty, prompt for their ISO and store its path. - print("Looking for some ISO data in " + UniversalIsoPath + "\\jak1\\") + print("Looking for some ISO data in " + UniversalIsoPath + "//" + GAME + "//") print("We did not find ISO data from a previous mod, lets ask for some!") # prompt for ISO file @@ -405,6 +503,18 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE): if pathlib.Path(iso_path).is_file: if not (pathlib.Path(iso_path).suffix).lower() == ".iso": 1 / 0 + if (GAME == "jak2"): + iso_file = iso_path + output_directory = UniversalIsoPath + "//" + GAME + "//" + + extraction_successful = False + + while not extraction_successful: + extraction_successful = extract_iso(iso_file, output_directory) + + if not extraction_successful: + print("Extraction failed. Retrying in 5 seconds...") + time.sleep(5) # extract update print("Extracting update") TempDir = InstallDir + "/temp" @@ -426,12 +536,12 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE): try_remove_dir(TempDir) replaceText( - InstallDir + r"\data\goal_src\jak1\pc\pckernel.gc", + InstallDir + r"\data\goal_src" + "//" + GAME + "//" + "pc\pckernel.gc", "Playing Jak and Daxter: The Precursor Legacy", "Playing " + MOD_NAME, ) replaceText( - InstallDir + r"\data\goal_src\jak1\pc\pckernel.gc", + InstallDir + r"\data\goal_src" + "//" + GAME + "//" + "pc\pckernel.gc", "/pc-settings.gc", r"/" + MOD_ID + "-settings.gc", ) @@ -443,33 +553,89 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE): try_kill_process("goalc.exe") print("Done update starting extractor This one can take a few moments! \n") - #extract and compile, but dont boot the game so we can move the iso files - extractor_command_list = [InstallDir + "\extractor.exe", "-f", iso_path , "-e", "-v", "-d", "-c"] - print(extractor_command_list) - subprocess.Popen(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir)) - - # move the extrated contents to the universal launchers directory for next time. - if not (exists((UniversalIsoPath + r"\jak1\Z6TAIL.DUP"))): + #Extract and compile + if(GAME == "jak1"): + extractor_command_list = [InstallDir + "\extractor.exe", "-f", iso_path , "-e", "-v", "-d", "-c"] + print(extractor_command_list) + subprocess.Popen(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir)) while process_exists("extractor.exe"): print("extractor.exe still running, sleeping for 1s") time.sleep(1) + + if(GAME == "jak2"): + + decompiler_command_list = [InstallDir + "\decompiler.exe", + "./data/decompiler/config/jak2/jak2_config.jsonc", + UniversalIsoPath, + "./data/decompiler_out", + "--version", + "ntsc_v1", + "--config-override", + '{"decompile_code": false}' + ] + print(decompiler_command_list) + subprocess.Popen(decompiler_command_list, shell=True, cwd=os.path.abspath(InstallDir)) + print("opened decompiler") + + #wait for decompiler before starting goalc + + while process_exists("decompiler.exe"): + print("decompiler.exe still running, sleeping for 1s") + time.sleep(1) + + goalc_command_list = [InstallDir + "\goalc.exe", + "--proj-path", + InstallDir + "\\data", + "--game", + "jak2", + "-c", + "(mi) (e)" + ] + + print(goalc_command_list) + shutil.copytree( UniversalIsoPath + "//" + GAME + "//", InstallDir + "/data/iso_data/" + GAME) + - #cleanup and remove a corrupted iso - if os.path.exists(UniversalIsoPath ) and os.path.isdir(UniversalIsoPath ): - print("Removing corrupted iso destination...") - shutil.rmtree(UniversalIsoPath + "/jak1") - print("corrupt iso removed.") + subprocess.Popen(goalc_command_list, shell=True, cwd=os.path.abspath(InstallDir)) + + # move the extrated contents to the universal launchers directory for next time. + + while process_exists("extractor.exe"): + print("extractor.exe still running, sleeping for 1s") + time.sleep(1) + + + while process_exists("goalc.exe"): + print("goalc.exe still running, sleeping for 1s") + time.sleep(1) + + + + #should be good to move iso now - shutil.move(InstallDir + "/data/iso_data/jak1", UniversalIsoPath ) - print("copying " + InstallDir + "/data/iso_data" + "to " + UniversalIsoPath ) + + path_to_remove = InstallDir + "/data/iso_data/" + GAME + if os.path.exists(path_to_remove): + shutil.rmtree(path_to_remove) + print(f"Path '{path_to_remove}' removed successfully.") + else: + print(f"Path '{path_to_remove}' does not exist.") + #print("copying " + InstallDir + "/data/iso_data/" + GAME + "to " + UniversalIsoPath ) #keep checking to make sure the move is in a finished state - while not (exists((UniversalIsoPath + r"\jak1\Z6TAIL.DUP"))): + while not (exists((UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"))): time.sleep(1) - + + if exists(InstallDir + "/" + ExecutableName): + LastWrite = datetime.utcfromtimestamp( + pathlib.Path(InstallDir + "/" + ExecutableName).stat().st_mtime + ) + NotExtracted = bool(not (exists(UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"))) + NotCompiled = bool(not (exists(InstallDir + r"\data\out" + "//" + GAME + "//" + "fr3\GAME.fr3"))) + needUpdate = bool((LastWrite < LatestRel) or (NotExtracted) or NotCompiled) if(NotExtracted): - print("Error! Iso data does not appear to be extracted to " + UniversalIsoPath +r"\jak1\Z6TAIL.DUP") + print("Error! Iso data does not appear to be extracted to " + UniversalIsoPath +"//" + GAME + "//" + "Z6TAIL.DUP") print("Will ask user to provide ISO") if(NotCompiled): print("Error! The game is not compiled") @@ -486,4 +652,4 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE): # if we dont need to update, then close any open instances of the game and just launch it print("Game is up to date!") print("Launching now!") - launch_local(MOD_ID) + launch_local(MOD_ID, GAME) diff --git a/utils/launcherUtilsbackup.py b/utils/launcherUtilsbackup.py new file mode 100644 index 0000000..e0f91b3 --- /dev/null +++ b/utils/launcherUtilsbackup.py @@ -0,0 +1,557 @@ +# -*- coding: utf-8 -*- +""" +Created on Fri Aug 12 06:51:37 2022 + +@author: Zed +""" +from datetime import datetime +from os.path import exists +from tkinter import filedialog +from utils import githubUtils +import json +import os +import pathlib +import progressbar +import requests +import shutil +import subprocess +import sys +import time +import tkinter as tk +import urllib.request +import zipfile +from appdirs import AppDirs +import platform +import stat + + +EXTRACT_ON_UPDATE = "true" +FILE_DATE_TO_CHECK = "gk.exe" +UPDATE_FILE_EXTENTION = ".zip" + +# Folder where script is placed, It looks in this for the Exectuable +if getattr(sys, "frozen", False): + LauncherDir = os.path.dirname(os.path.realpath(sys.executable)) +elif __file__: + LauncherDir = os.path.dirname(__file__) + +extractOnUpdate = bool(str(EXTRACT_ON_UPDATE).replace("t", "T").replace("f", "F")) +ExecutableName = str( + FILE_DATE_TO_CHECK +) # Executable we're checking the 'modified' time of +FileExt = str( + UPDATE_FILE_EXTENTION +) # content_type of the .deb release is also "application\zip", so rely on file ext +FileIdent = "" # If we ever get to multiple .zip files in a release, include other identifying information from the name +dirs = AppDirs(roaming=True) +currentOS = platform.system() +ModFolderPATH = os.path.join(dirs.user_data_dir, "OpenGOAL-Mods", "") +AppdataPATH = dirs.user_data_dir + + +pbar = None + + +def installedlist(PATH): + print(PATH) + scanDir = PATH + directories = [ + d + for d in os.listdir(scanDir) + if os.path.isdir(os.path.join(os.path.abspath(scanDir), d)) + ] + print(directories) + for i in directories: + print(i) + print(os.path.dirname(os.path.dirname(PATH))) + + +def show_progress(block_num, block_size, total_size): + if total_size > 0: + global pbar + if pbar is None: + pbar = progressbar.ProgressBar(maxval=total_size) + pbar.start() + + downloaded = block_num * block_size + + if downloaded < total_size: + pbar.update(downloaded) + else: + pbar.finish() + pbar = None + + +def process_exists(process_name): + call = "TASKLIST", "/FI", "imagename eq %s" % process_name + try: + # use buildin check_output right away + output = subprocess.check_output(call).decode() + # check in last line for process name + last_line = output.strip().split("\r\n")[-1] + # because Fail message could be translated + return last_line.lower().startswith(process_name.lower()) + except: + return False + + +def try_kill_process(process_name): + if process_exists(process_name): + os.system("taskkill /f /im " + process_name) + + +def try_remove_file(file): + if exists(file): + os.remove(file) + + +def try_remove_dir(dir): + if exists(dir): + shutil.rmtree(dir) + + +def local_mod_image(MOD_ID): + path = ModFolderPATH + MOD_ID + "\\ModImage.png" + if exists(path): + return path + return None + + +def launch_local(MOD_ID, GAME): + try: + # Close Gk and goalc if they were open. + try_kill_process("gk.exe") + try_kill_process("goalc.exe") + + time.sleep(1) + InstallDir = ModFolderPATH + MOD_ID + + UniversalIsoPath = AppdataPATH + "\OpenGOAL\jak1\mods\data\iso_data" + + GKCOMMANDLINElist = [ + os.path.abspath(InstallDir + "\gk.exe"), # Using os.path.abspath to get the absolute path. + "--proj-path", + os.path.abspath(InstallDir + "\\data"), # Using absolute path for data folder too. + "-boot", + "-fakeiso", + "-v", + ] + if(GAME == "jak2"): + GKCOMMANDLINElist = [ + InstallDir + "\gk.exe", + "--proj-path", + InstallDir + "\\data", + "-boot", + "-fakeiso", + "-v", + "--game", + "jak2", + "debug", + ] + print(GKCOMMANDLINElist) + subprocess.Popen(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir)) + except Exception as e: # Catch all exceptions and print the error message. + return str(e) + + +def openFolder(path): + FILEBROWSER_PATH = os.path.join(os.getenv("WINDIR"), "explorer.exe") + subprocess.run([FILEBROWSER_PATH, path]) + + +def reinstall(MOD_ID): + InstallDir = ModFolderPATH + MOD_ID + AppdataPATH = os.getenv("APPDATA") + UniversalIsoPath = AppdataPATH + "\OpenGOAL\jak1\mods\data\iso_data" + + GKCOMMANDLINElist = [ + InstallDir + "\gk.exe", + "--proj-path", + InstallDir + "\\data", + "-boot", + "-fakeiso", + "-v", + ] + + # if ISO_DATA has content, store this path to pass to the extractor + if exists(UniversalIsoPath + r"\jak1\Z6TAIL.DUP"): + iso_path = UniversalIsoPath + "\jak1" + + else: + # if ISO_DATA is empty, prompt for their ISO and store its path. + root = tk.Tk() + print("Please select your iso.") + root.title("Select ISO") + root.geometry("230x1") + iso_path = filedialog.askopenfilename() + root.destroy() + if pathlib.Path(iso_path).is_file: + if not (pathlib.Path(iso_path).suffix).lower() == ".iso": + 1 / 0 + + # Close Gk and goalc if they were open. + try_kill_process("gk.exe") + try_kill_process("goalc.exe") + print("Done update starting extractor\n") + if currentOS == "Windows": + extractor_command_list = [ + os.path.join(InstallDir, "extractor.exe"), + "-f", + iso_path, + ] + if currentOS == "Linux": + # We need to give the executibles execute permissions in Linux but this doesn't work + # chmod_command_list = ["cd" + os.path.join(LauncherDir), "chmod +x extractor goalc gk"] + # subprocess.Popen(chmod_command_list) + os.chmod(os.path.join(LauncherDir, "extractor"), stat.S_IXOTH) + print("Done chmods!") + # Then we need to call the Linux extractor when we do the next Popen + extractor_command_list = [ + os.path.join(LauncherDir), + "./extractor -f" + iso_path + "--proj-path" + InstallDir, + ] + print(extractor_command_list) + + subprocess.Popen(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir)) + + # wait for extractor to finish + while process_exists("extractor.exe"): + print("extractor.exe still running, sleeping for 1s") + time.sleep(1) + + # move the extrated contents to the universal launchers directory for next time. + if not (exists((UniversalIsoPath + r"\jak1\Z6TAIL.DUP"))): + + # os.makedirs(AppdataPATH + "\OpenGOAL-Launcher\data\iso_data") + print("The new directory is created!") + shutil.move(InstallDir + "/data/iso_data", "" + UniversalIsoPath + "") + + # try_remove_dir(InstallDir + "/data/iso_data") + # os.symlink("" + UniversalIsoPath +"", InstallDir + "/data/iso_data") + + +def replaceText(path, search_text, replace_text): + # Check if the file exists + if not os.path.isfile(path): + print(f"File '{path}' does not exist.") + return + + # Open the file in read-only mode + with open(path, "r") as file: + data = file.read() + + # Perform the search and replace operation + data = data.replace(search_text, replace_text) + + # Open the file in write mode to write the replaced content + with open(path, "w") as file: + file.write(data) + + print(f"Text replaced successfully in file '{path}'.") + + +def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): + print(GAME) + print(GAME) + print(GAME) + print(GAME) + print(GAME) + print(GAME) + print(GAME) + print(GAME) + print(GAME) + print(GAME) + print(GAME) + print(GAME) + if URL is None: + return + + # start of update check method + # Github API Call + launchUrl = URL + if LINK_TYPE == githubUtils.LinkTypes.BRANCH: + launchUrl = githubUtils.branchToApiURL(URL) + LatestRelAssetsURL = "" + + print("\nlaunching from " + launchUrl) + PARAMS = {"address": "yolo"} + r = json.loads(json.dumps(requests.get(url=launchUrl, params=PARAMS).json())) + + # paths + InstallDir = ModFolderPATH + MOD_ID + AppdataPATH = os.getenv("APPDATA") + UniversalIsoPath = AppdataPATH + "\OpenGOAL\jak1\mods\data\iso_data" + + GKCOMMANDLINElist = [ + InstallDir + "\gk.exe", + "--proj-path", + InstallDir + "\\data", + "-boot", + "-fakeiso", + "-v", + ] + + if (GAME == "jak2"): + GKCOMMANDLINElist = [ + InstallDir + "\gk.exe", + "--proj-path", + InstallDir + "\\data", + "-boot", + "-fakeiso", + "-v", + "--game", + "jak2", + "debug", + ] + + # store Latest Release and check our local date too. + if LINK_TYPE == githubUtils.LinkTypes.BRANCH: + LatestRel = datetime.strptime( + r.get("commit") + .get("commit") + .get("author") + .get("date") + .replace("T", " ") + .replace("Z", ""), + "%Y-%m-%d %H:%M:%S", + ) + LatestRelAssetsURL = githubUtils.branchToArchiveURL(URL) + elif LINK_TYPE == githubUtils.LinkTypes.RELEASE: + LatestRel = datetime.strptime( + r[0].get("published_at").replace("T", " ").replace("Z", ""), + "%Y-%m-%d %H:%M:%S", + ) + assets = json.loads(json.dumps(requests.get(url=r[0].get("assets_url"), params=PARAMS).json())) + for asset in assets: + if "linux" not in asset.get("name") and "macos" not in asset.get("name") and "json" not in asset.get("name"): + LatestRelAssetsURL = asset.get("browser_download_url") + break + + # response = requests.get(url=LatestRelAssetsURL, params=PARAMS) + # content_type = response.headers["content-type"] + + LastWrite = datetime(2020, 5, 17) + if exists(InstallDir + "/" + ExecutableName): + LastWrite = datetime.utcfromtimestamp( + pathlib.Path(InstallDir + "/" + ExecutableName).stat().st_mtime + ) + + # update checks + + if(GAME == "jak1"): + NotExtracted = bool(not (exists(UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP"))) + NotCompiled = bool(not (exists(InstallDir + r"\data\out\jak1\fr3\GAME.fr3"))) + needUpdate = bool((LastWrite < LatestRel) or (NotExtracted) or NotCompiled) + if(GAME == "jak2"): + NotExtracted = bool(not (exists(UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP"))) + NotCompiled = bool(not (exists(InstallDir + r"\data\out\jak2\fr3\GAME.fr3"))) + needUpdate = bool((LastWrite < LatestRel) or (NotExtracted) or NotCompiled) + + print("Currently installed version created on: " + LastWrite.strftime('%Y-%m-%d %H:%M:%S')) + print("Newest version created on: " + LatestRel.strftime('%Y-%m-%d %H:%M:%S')) + if(NotExtracted): + print("Error! Iso data does not appear to be extracted to " + UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP") + print("Will ask user to provide ISO") + if(NotCompiled): + print("Error! The game is not compiled") + if((LastWrite < LatestRel)): + print("Looks like we need to download a new update!") + print(LastWrite) + print(LatestRel) + print("Is newest posted update older than what we have installed? " + str((LastWrite < LatestRel))) + + if(GAME == "jak1"): + # attempt to migrate any old settings files from using MOD_NAME to MOD_ID + if exists(AppdataPATH + "\OpenGOAL\jak1\settings\\" + MOD_NAME + "-settings.gc"): + # just to be safe delete the migrated settings file if it already exists (shouldn't happen but prevents rename from failing below) + if exists(AppdataPATH + "\OpenGOAL\jak1\settings\\" + MOD_ID + "-settings.gc"): + os.remove( + AppdataPATH + "\OpenGOAL\jak1\settings\\" + MOD_ID + "-settings.gc" + ) + + # rename settings file + os.rename( + AppdataPATH + "\OpenGOAL\jak1\settings\\" + MOD_NAME + "-settings.gc", + AppdataPATH + "\OpenGOAL\jak1\settings\\" + MOD_ID + "-settings.gc", + ) + # force update to ensure we recompile with adjusted settings filename in pckernel.gc + needUpdate = True + + if (needUpdate): + + #start the actual update method if needUpdate is true + print("\nNeed to update") + print("Starting Update...") + # Close Gk and goalc if they were open. + try_kill_process("gk.exe") + try_kill_process("goalc.exe") + + # download update from github + # Create a new directory because it does not exist + try_remove_dir(InstallDir + "/temp") + if not os.path.exists(InstallDir + "/temp"): + print("Creating install dir: " + InstallDir) + os.makedirs(InstallDir + "/temp") + + response = requests.get(LatestRelAssetsURL) + if response.history: + print("Request was redirected") + for resp in response.history: + print(resp.status_code, resp.url) + print("Final destination:") + print(response.status_code, response.url) + LatestRelAssetsURL = response.url + + else: + print("Request was not redirected") + + print("Downloading update from " + LatestRelAssetsURL) + file = urllib.request.urlopen(LatestRelAssetsURL) + print() + print(str("File size is ") + str(file.length)) + urllib.request.urlretrieve( + LatestRelAssetsURL, InstallDir + "/temp/updateDATA.zip", show_progress + ) + print("Done downloading") + r = requests.head(LatestRelAssetsURL, allow_redirects=True) + + # delete any previous installation + print("Removing previous installation " + InstallDir) + try_remove_dir(InstallDir + "/data") + try_remove_dir(InstallDir + "/.github") + try_remove_file(InstallDir + "/gk.exe") + try_remove_file(InstallDir + "/goalc.exe") + try_remove_file(InstallDir + "/extractor.exe") + try_remove_file(InstallDir + "/decompiler.exe") + + + #if ISO_DATA has content, store this path to pass to the extractor + if (exists(UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP")): + + print("We found ISO data from a previous mod installation! Lets use it!") + print("Found in " + UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP") + iso_path = UniversalIsoPath + "\\" +GAME + else: + #if ISO_DATA is empty, prompt for their ISO and store its path. + + #cleanup and remove a corrupted iso + if os.path.exists(UniversalIsoPath + "\\" + GAME) and os.path.isdir(UniversalIsoPath + "\\" + GAME): + print("Removing corrupted iso destination... " + UniversalIsoPath + "\\" + GAME + "") + shutil.rmtree(UniversalIsoPath + "\\" + GAME) + print("corrupt iso removed.") + + print("Looking for some ISO data in " + UniversalIsoPath + "\\" +GAME) + + print("We did not find ISO data from a previous mod, lets ask for some!") + # prompt for ISO file + root = tk.Tk() + root.title("Select ISO") + root.geometry("230x1") + + top_level = tk.Toplevel(root) + top_level.attributes("-topmost", True) # Set the file dialog to stay on top + + iso_path = filedialog.askopenfilename(parent=top_level) + root.destroy() + if pathlib.Path(iso_path).is_file: + if not (pathlib.Path(iso_path).suffix).lower() == ".iso": + 1 / 0 + # extract update + print("Extracting update") + TempDir = InstallDir + "/temp" + with zipfile.ZipFile(TempDir + "/updateDATA.zip", "r") as zip_ref: + zip_ref.extractall(TempDir) + + # delete the update archive + try_remove_file(TempDir + "/updateDATA.zip") + + SubDir = TempDir + if LINK_TYPE == githubUtils.LinkTypes.BRANCH or len(os.listdir(SubDir)) == 1: + # for branches, the downloaded zip puts all files one directory down + SubDir = SubDir + "/" + os.listdir(SubDir)[0] + + print("Moving files from " + SubDir + " up to " + InstallDir) + allfiles = os.listdir(SubDir) + for f in allfiles: + shutil.move(SubDir + "/" + f, InstallDir + "/" + f) + try_remove_dir(TempDir) + + if(GAME=="jak1"): + replaceText( + InstallDir + r"\data\goal_src\jak1\pc\pckernel.gc", + "Playing Jak and Daxter: The Precursor Legacy", + "Playing " + MOD_NAME, + ) + replaceText( + InstallDir + r"\data\goal_src\jak1\pc\pckernel.gc", + "/pc-settings.gc", + r"/" + MOD_ID + "-settings.gc", + ) + + # if extractOnUpdate is True, check their ISO_DATA folder + + # Close Gk and goalc if they were open. + try_kill_process("gk.exe") + try_kill_process("goalc.exe") + print("Done update starting extractor This one can take a few moments! \n") + + #extract and compile, but dont boot the game so we can move the iso files + + if(GAME == "jak1"): + extractor_command_list = [InstallDir + "\extractor.exe", "-f", iso_path , "-e", "-v", "-d", "-c"] + print(extractor_command_list) + subprocess.Popen(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir)) + + # move the extrated contents to the universal launchers directory for next time. + + while process_exists("extractor.exe"): + print("extractor.exe still running, sleeping for 1s") + time.sleep(1) + + if(GAME == "jak2"): + decompiler_command_list = [InstallDir + "\decompiler.exe", + "./data/decompiler/config/jak2/jak2_config.jsonc", + iso_path, + "./data/decompiler_out", + "--version" + "\"ntsc_v1\"", + "--config-override", + "{\"decompile_code\": false}"] + print(decompiler_command_list) + subprocess.Popen(decompiler_command_list, shell=True, cwd=os.path.abspath(InstallDir)) + + # move the extrated contents to the universal launchers directory for next time. + if not (exists((UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP"))): + while process_exists("decompiler.exe"): + print("decompiler.exe still running, sleeping for 1s") + time.sleep(1) + + + if not os.path.exists(UniversalIsoPath + "\\" + GAME): + shutil.move(InstallDir + "/data/iso_data"+ "\\" + GAME, UniversalIsoPath) + print("copying " + InstallDir + "/data/iso_data"+ "\\" + GAME + "to " + UniversalIsoPath ) + + #keep checking to make sure the move is in a finished state + while not (exists((UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP"))): + print("waiting for iso at " + UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP") + time.sleep(1) + + if(NotExtracted): + print("Error! Iso data does not appear to be extracted to " + UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP") + print("Will ask user to provide ISO") + if(NotCompiled): + print("Error! The game is not compiled") + if((LastWrite < LatestRel)): + print("Looks like we need to download a new update!") + print(LastWrite) + print(LatestRel) + print("Is newest posted update older than what we have installed? " + str((LastWrite < LatestRel))) + + #ok launch game :D + subprocess.Popen(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir)) + + else: + # if we dont need to update, then close any open instances of the game and just launch it + print("Game is up to date!") + print("Launching now!") + launch_local(MOD_ID, GAME) From 6c2bf3e5d1a4d49099cd82e9fb3ef8e1123570f5 Mon Sep 17 00:00:00 2001 From: ZedB0T <89345505+Zedb0T@users.noreply.github.com> Date: Mon, 21 Aug 2023 09:41:56 -0400 Subject: [PATCH 04/25] Add jak 2 manual end to end no pycdlib --- utils/launcherUtils.py | 151 ++++++++++++++++++++++++++++++++--------- 1 file changed, 119 insertions(+), 32 deletions(-) diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index d8351d6..98a5587 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -25,6 +25,7 @@ import stat import pycdlib from pathlib import Path +import time EXTRACT_ON_UPDATE = "true" FILE_DATE_TO_CHECK = "gk.exe" @@ -180,16 +181,28 @@ def reinstall(MOD_ID): iso_path = UniversalIsoPath + "\\" + GAME else: - # if ISO_DATA is empty, prompt for their ISO and store its path. - root = tk.Tk() - print("Please select your iso.") - root.title("Select ISO") - root.geometry("230x1") - iso_path = filedialog.askopenfilename() - root.destroy() - if pathlib.Path(iso_path).is_file: - if not (pathlib.Path(iso_path).suffix).lower() == ".iso" or not (pathlib.Path(iso_path).suffix).lower() == ".zip": - 1 / 0 + if GAME == "jak1": + # if ISO_DATA is empty, prompt for their ISO and store its path. + root = tk.Tk() + print("Please select your iso.") + root.title("Select ISO") + root.geometry("230x1") + iso_path = filedialog.askopenfilename() + root.destroy() + if pathlib.Path(iso_path).is_file: + if not (pathlib.Path(iso_path).suffix).lower() == ".iso" or not (pathlib.Path(iso_path).suffix).lower() == ".zip": + 1 / 0 + if GAME == "jak2": + # if ISO_DATA is empty, prompt for their ISO and store its path. + root = tk.Tk() + print("Please select your JAK2") + root.title("Select ISO JAK222222222222S") + root.geometry("230x1") + iso_path = filedialog.askopenfilename() + root.destroy() + if pathlib.Path(iso_path).is_file: + if not (pathlib.Path(iso_path).suffix).lower() == ".iso" or not (pathlib.Path(iso_path).suffix).lower() == ".zip": + 1 / 0 print("Extraction completed successfully.") @@ -307,7 +320,31 @@ def extract_iso(ISO_PATH, EXTRACT_DIR): iso.close() return True - +def open_browser_link(): + url = "https://google.com" # Replace with the desired URL + if sys.platform.startswith('linux'): + subprocess.Popen(["xdg-open", url]) + elif sys.platform.startswith('win'): + subprocess.Popen(["start", url], shell=True) + elif sys.platform.startswith('darwin'): + subprocess.Popen(["open", url]) + else: + print("Unsupported platform") + +def open_folder(path): + folder_path = path # Replace with the desired folder path + if not os.path.exists(path): + # Create the directory + try: + os.makedirs(path) + print(f"Directory '{path}' created successfully.") + except OSError as e: + print(f"Error creating directory '{path}': {e}") + os.startfile(folder_path) + +def divide_by_zero(): + 1 / 0 + def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): print(GAME) print(GAME) @@ -482,39 +519,86 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): iso_path = UniversalIsoPath + "\\" + GAME else: #cleanup and remove a corrupted iso - if os.path.exists(UniversalIsoPath) and os.path.isdir(UniversalIsoPath) and not (exists((UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"))): + if os.path.exists(UniversalIsoPath + "//" + GAME) and os.path.isdir(UniversalIsoPath) and not (exists((UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"))): print("Removing corrupted iso destination...") shutil.rmtree(UniversalIsoPath + "//" + GAME) print("corrupt iso removed.") + if GAME == "jak2": + os.makedirs(UniversalIsoPath + "//" + GAME) #if ISO_DATA is empty, prompt for their ISO and store its path. + if GAME == "jak1": + # if ISO_DATA is empty, prompt for their ISO and store its path. + root = tk.Tk() + print("Please select your iso.") + root.title("Select ISO") + root.geometry("230x1") + iso_path = filedialog.askopenfilename() + root.destroy() + if pathlib.Path(iso_path).is_file: + if not (pathlib.Path(iso_path).suffix).lower() == ".iso" or not (pathlib.Path(iso_path).suffix).lower() == ".zip": + 1 / 0 + if GAME == "jak2": + # root = tk.Tk() + # root.title("Game Actions") + # root.geometry("300x100") + + # button1 = tk.Button(root, text="Open Browser Link", command=open_browser_link) + # button1.pack(pady=10) + + # button2 = tk.Button(root, text="Open Folder in Explorer", command=open_folder(UniversalIsoPath)) + # button2.pack(pady=5) + + # button3 = tk.Button(root, text="Divide by Zero", command=root.destroy) + # button3.pack(pady=5) + + # iso_path = UniversalIsoPath + "//" + GAME + "//" + + #root.mainloop() + while not (exists((UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"))): + print("Didnt find ztail in " + UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP" + " sleeping") + time.sleep(1) + if (exists((UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"))): + print("ok we found the iso data! waiting 45 seconds to make sure the copy has time to finish") + print("dont touch anything! This will take a moment!") + start_time = time.time() + elapsed_time = 0 + remaining_time = 45 + + while elapsed_time < 45: + time.sleep(1) # Sleep for 1 second + elapsed_time = time.time() - start_time + remaining_time = max(0, 45 - elapsed_time) + print(f"Time remaining: {remaining_time:.1f} seconds", end='\r') print("Looking for some ISO data in " + UniversalIsoPath + "//" + GAME + "//") print("We did not find ISO data from a previous mod, lets ask for some!") # prompt for ISO file - root = tk.Tk() - root.title("Select ISO") - root.geometry("230x1") + # root = tk.Tk() + # root.title("Select ISO") + # root.geometry("230x1") - top_level = tk.Toplevel(root) - top_level.attributes("-topmost", True) # Set the file dialog to stay on top + # top_level = tk.Toplevel(root) + # top_level.attributes("-topmost", True) # Set the file dialog to stay on top - iso_path = filedialog.askopenfilename(parent=top_level) - root.destroy() - if pathlib.Path(iso_path).is_file: - if not (pathlib.Path(iso_path).suffix).lower() == ".iso": - 1 / 0 - if (GAME == "jak2"): - iso_file = iso_path - output_directory = UniversalIsoPath + "//" + GAME + "//" + # iso_path = filedialog.askopenfilename(parent=top_level) + # root.destroy() + # if pathlib.Path(iso_path).is_file: + # if not (pathlib.Path(iso_path).suffix).lower() == ".iso": + # 1 / 0 - extraction_successful = False + # if (GAME == "jak2"): + # #iso_file = iso_path + # iso_file = UniversalIsoPath + "//" + GAME + "//" + # output_directory = UniversalIsoPath + "//" + GAME + "//" - while not extraction_successful: - extraction_successful = extract_iso(iso_file, output_directory) + # extraction_successful = False - if not extraction_successful: - print("Extraction failed. Retrying in 5 seconds...") - time.sleep(5) + # while not extraction_successful: + # extraction_successful = extract_iso(iso_file, output_directory) + + # if not extraction_successful: + # print("Extraction failed. Retrying in 5 seconds...") + # time.sleep(5) # extract update print("Extracting update") TempDir = InstallDir + "/temp" @@ -578,7 +662,8 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): print("opened decompiler") #wait for decompiler before starting goalc - + #Decompiler + time.sleep(3) while process_exists("decompiler.exe"): print("decompiler.exe still running, sleeping for 1s") time.sleep(1) @@ -598,8 +683,10 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): subprocess.Popen(goalc_command_list, shell=True, cwd=os.path.abspath(InstallDir)) + # move the extrated contents to the universal launchers directory for next time. + time.sleep(5) while process_exists("extractor.exe"): print("extractor.exe still running, sleeping for 1s") time.sleep(1) From 43a703df1fb0cf8034ad8224e27b2cc512f59c5c Mon Sep 17 00:00:00 2001 From: ZedB0T <89345505+Zedb0T@users.noreply.github.com> Date: Mon, 21 Aug 2023 10:39:52 -0400 Subject: [PATCH 05/25] Fix some comments, cleanup some things, add reinstall for jak 2 --- openGOALModLauncher.py | 6 +- utils/launcherUtils.py | 164 +++++++++++++++++------------------------ 2 files changed, 72 insertions(+), 98 deletions(-) diff --git a/openGOALModLauncher.py b/openGOALModLauncher.py index 7ea3c5f..e03d033 100644 --- a/openGOALModLauncher.py +++ b/openGOALModLauncher.py @@ -586,7 +586,11 @@ def reset(): else: sg.Popup("Selected mod is not installed", keep_on_top=True, icon=iconfile) elif event == "-REINSTALL-": + tmpModName = window["-SELECTEDMODNAME-"].get() tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] + tmpModURL = window["-SELECTEDMODNAME-"].metadata["url"] + tmpGame = window["-SELECTEDMODNAME-"].metadata["game"] + [linkType, tmpModURL] = githubUtils.identifyLinkType(tmpModURL) subfolders = [f.name for f in os.scandir(ModFolderPATH) if f.is_dir()] if tmpModSelected in subfolders: @@ -598,7 +602,7 @@ def reset(): icon=iconfile, ) if ans == "OK": - launcherUtils.reinstall(tmpModSelected) + launcherUtils.reinstall(tmpModURL, tmpModSelected, tmpModName, linkType, tmpGame) reset() else: sg.Popup("Selected mod is not installed", keep_on_top=True, icon=iconfile) diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index 98a5587..aa9e00c 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -161,11 +161,23 @@ def openFolder(path): FILEBROWSER_PATH = os.path.join(os.getenv("WINDIR"), "explorer.exe") subprocess.run([FILEBROWSER_PATH, path]) - -def reinstall(MOD_ID): +#tmpModURL, tmpModSelected, tmpModName, linkType, tmpGame +def reinstall(URL, MOD_ID, MODNAME, LINKTYPE, GAME): InstallDir = ModFolderPATH + MOD_ID AppdataPATH = os.getenv("APPDATA") UniversalIsoPath = AppdataPATH + "\OpenGOAL\mods\data\iso_data" + #reinstall has a lot of duplicated logic not sure if there is a reason for this yet, but for now for jak 2 we can just delte the directory then call the install/launch function + if GAME == "jak2": + path_to_remove = InstallDir + if os.path.exists(path_to_remove): + shutil.rmtree(path_to_remove) + print(f"Path '{path_to_remove}' removed successfully.") + else: + print(f"Path '{path_to_remove}' does not exist.") + + launch(URL, MOD_ID, MODNAME, LINKTYPE, GAME) + return + GKCOMMANDLINElist = [ InstallDir + "\gk.exe", @@ -192,19 +204,6 @@ def reinstall(MOD_ID): if pathlib.Path(iso_path).is_file: if not (pathlib.Path(iso_path).suffix).lower() == ".iso" or not (pathlib.Path(iso_path).suffix).lower() == ".zip": 1 / 0 - if GAME == "jak2": - # if ISO_DATA is empty, prompt for their ISO and store its path. - root = tk.Tk() - print("Please select your JAK2") - root.title("Select ISO JAK222222222222S") - root.geometry("230x1") - iso_path = filedialog.askopenfilename() - root.destroy() - if pathlib.Path(iso_path).is_file: - if not (pathlib.Path(iso_path).suffix).lower() == ".iso" or not (pathlib.Path(iso_path).suffix).lower() == ".zip": - 1 / 0 - - print("Extraction completed successfully.") # Close Gk and goalc if they were open. try_kill_process("gk.exe") @@ -345,16 +344,11 @@ def open_folder(path): def divide_by_zero(): 1 / 0 +def getDecompiler(path): + #check if we have decompiler in the path, if not check if we have a backup, if so use it, if not download a backup then use it + return + def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): - print(GAME) - print(GAME) - print(GAME) - print(GAME) - print(GAME) - print(GAME) - print(GAME) - print(GAME) - print(GAME) if URL is None: return @@ -373,11 +367,15 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): InstallDir = ModFolderPATH + MOD_ID AppdataPATH = os.getenv("APPDATA") UniversalIsoPath = AppdataPATH + "\OpenGOAL\mods\data\iso_data" + DataFolder = InstallDir + "\\data" + GkPATH = InstallDir + "\gk.exe" + GoalCPATH = InstallDir + "\goalc.exe" + DecompilerPATH = InstallDir + "\decompiler.exe" GKCOMMANDLINElist = [ - InstallDir + "\gk.exe", + GkPATH, "--proj-path", - InstallDir + "\\data", + DataFolder, "-boot", "-fakeiso", "-v", @@ -385,9 +383,9 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): if (GAME == "jak2"): GKCOMMANDLINElist = [ - InstallDir + "\gk.exe", + GkPATH, "--proj-path", - InstallDir + "\\data", + DataFolder, "-v", "--game", "jak2", @@ -510,7 +508,11 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): try_remove_file(InstallDir + "/gk.exe") try_remove_file(InstallDir + "/goalc.exe") try_remove_file(InstallDir + "/extractor.exe") - + #jak2hack + try_remove_file(InstallDir + "/decompiler.exe") + print("Looking for some ISO data in " + UniversalIsoPath + "//" + GAME + "//") + + #if ISO_DATA has content, store this path to pass to the extractor if (exists(UniversalIsoPath +"//" + GAME + "//" + "Z6TAIL.DUP")): @@ -518,11 +520,14 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): print("Found in " + UniversalIsoPath +"//" + GAME + "//" + "Z6TAIL.DUP") iso_path = UniversalIsoPath + "\\" + GAME else: + print("We did not find ISO data from a previous mod, lets ask for some!") #cleanup and remove a corrupted iso if os.path.exists(UniversalIsoPath + "//" + GAME) and os.path.isdir(UniversalIsoPath) and not (exists((UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"))): print("Removing corrupted iso destination...") shutil.rmtree(UniversalIsoPath + "//" + GAME) print("corrupt iso removed.") + #jak2hack + #since we are having users manually drop the iso into the folder creating it for them is nice :) if GAME == "jak2": os.makedirs(UniversalIsoPath + "//" + GAME) #if ISO_DATA is empty, prompt for their ISO and store its path. @@ -538,25 +543,10 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): if not (pathlib.Path(iso_path).suffix).lower() == ".iso" or not (pathlib.Path(iso_path).suffix).lower() == ".zip": 1 / 0 if GAME == "jak2": - # root = tk.Tk() - # root.title("Game Actions") - # root.geometry("300x100") - - # button1 = tk.Button(root, text="Open Browser Link", command=open_browser_link) - # button1.pack(pady=10) - - # button2 = tk.Button(root, text="Open Folder in Explorer", command=open_folder(UniversalIsoPath)) - # button2.pack(pady=5) - - # button3 = tk.Button(root, text="Divide by Zero", command=root.destroy) - # button3.pack(pady=5) - - # iso_path = UniversalIsoPath + "//" + GAME + "//" - - #root.mainloop() + #since extractor currently doesnt know about jak 2, we need to manually place the iso contents into the folder we expect while not (exists((UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"))): - print("Didnt find ztail in " + UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP" + " sleeping") - time.sleep(1) + print("Didnt find iso in " + UniversalIsoPath + "//" + GAME + "//" + " sleeping for 5 seconds, then checking again.") + time.sleep(5) if (exists((UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"))): print("ok we found the iso data! waiting 45 seconds to make sure the copy has time to finish") print("dont touch anything! This will take a moment!") @@ -569,43 +559,15 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): elapsed_time = time.time() - start_time remaining_time = max(0, 45 - elapsed_time) print(f"Time remaining: {remaining_time:.1f} seconds", end='\r') - print("Looking for some ISO data in " + UniversalIsoPath + "//" + GAME + "//") - - print("We did not find ISO data from a previous mod, lets ask for some!") - # prompt for ISO file - # root = tk.Tk() - # root.title("Select ISO") - # root.geometry("230x1") - - # top_level = tk.Toplevel(root) - # top_level.attributes("-topmost", True) # Set the file dialog to stay on top + - # iso_path = filedialog.askopenfilename(parent=top_level) - # root.destroy() - # if pathlib.Path(iso_path).is_file: - # if not (pathlib.Path(iso_path).suffix).lower() == ".iso": - # 1 / 0 - - # if (GAME == "jak2"): - # #iso_file = iso_path - # iso_file = UniversalIsoPath + "//" + GAME + "//" - # output_directory = UniversalIsoPath + "//" + GAME + "//" - - # extraction_successful = False - - # while not extraction_successful: - # extraction_successful = extract_iso(iso_file, output_directory) - - # if not extraction_successful: - # print("Extraction failed. Retrying in 5 seconds...") - # time.sleep(5) - # extract update + # extract mod zipped update print("Extracting update") TempDir = InstallDir + "/temp" with zipfile.ZipFile(TempDir + "/updateDATA.zip", "r") as zip_ref: zip_ref.extractall(TempDir) - # delete the update archive + # delete the mod zipped update archive try_remove_file(TempDir + "/updateDATA.zip") SubDir = TempDir @@ -617,8 +579,10 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): allfiles = os.listdir(SubDir) for f in allfiles: shutil.move(SubDir + "/" + f, InstallDir + "/" + f) + time.sleep(2) try_remove_dir(TempDir) + #replace the settings and discord RPC texts automatically before we build the game. replaceText( InstallDir + r"\data\goal_src" + "//" + GAME + "//" + "pc\pckernel.gc", "Playing Jak and Daxter: The Precursor Legacy", @@ -640,15 +604,15 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): #Extract and compile if(GAME == "jak1"): extractor_command_list = [InstallDir + "\extractor.exe", "-f", iso_path , "-e", "-v", "-d", "-c"] - print(extractor_command_list) + #print(extractor_command_list) subprocess.Popen(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir)) while process_exists("extractor.exe"): print("extractor.exe still running, sleeping for 1s") time.sleep(1) if(GAME == "jak2"): - - decompiler_command_list = [InstallDir + "\decompiler.exe", + getDecompiler(InstallDir) + decompiler_command_list = [DecompilerPATH, "./data/decompiler/config/jak2/jak2_config.jsonc", UniversalIsoPath, "./data/decompiler_out", @@ -657,7 +621,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): "--config-override", '{"decompile_code": false}' ] - print(decompiler_command_list) + #print(decompiler_command_list) subprocess.Popen(decompiler_command_list, shell=True, cwd=os.path.abspath(InstallDir)) print("opened decompiler") @@ -668,40 +632,46 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): print("decompiler.exe still running, sleeping for 1s") time.sleep(1) - goalc_command_list = [InstallDir + "\goalc.exe", + goalc_command_list = [GoalCPATH, "--proj-path", - InstallDir + "\\data", + DataFolder, "--game", "jak2", "-c", "(mi) (e)" ] - print(goalc_command_list) - shutil.copytree( UniversalIsoPath + "//" + GAME + "//", InstallDir + "/data/iso_data/" + GAME) + #print(goalc_command_list) + + # move the extrated contents to the universal launchers directory for next time. + + #shutil.copytree(UniversalIsoPath + "//" + GAME + "//", InstallDir + "/data/iso_data/" + GAME) + #should be good to move iso now + shutil.copytree(UniversalIsoPath + "//" + GAME + "//", InstallDir + "/data/iso_data/" + GAME) + #keep checking to make sure the move is in a finished state + while not (exists(InstallDir + "/data/iso_data/" + GAME + "//Z6TAIL.DUP")): + print(InstallDir + "/data/iso_data/" + GAME + "//Z6TAIL.DUP " + "Not found yet, sleeping then checking again to make sure the install finished") + time.sleep(5) + + #open GoalC to build jak2, for jak 1 extractor can handle this. + print("Opening the Compiler subprocess - Sleeping for 5 seconds so it has time to initalize.") subprocess.Popen(goalc_command_list, shell=True, cwd=os.path.abspath(InstallDir)) - - # move the extrated contents to the universal launchers directory for next time. - + time.sleep(5) while process_exists("extractor.exe"): print("extractor.exe still running, sleeping for 1s") time.sleep(1) - + #jak2hack this is only needed since extractor isnt aware of jak2 while process_exists("goalc.exe"): print("goalc.exe still running, sleeping for 1s") time.sleep(1) - - - #should be good to move iso now - path_to_remove = InstallDir + "/data/iso_data/" + GAME if os.path.exists(path_to_remove): shutil.rmtree(path_to_remove) @@ -710,10 +680,10 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): print(f"Path '{path_to_remove}' does not exist.") #print("copying " + InstallDir + "/data/iso_data/" + GAME + "to " + UniversalIsoPath ) - #keep checking to make sure the move is in a finished state - while not (exists((UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"))): - time.sleep(1) + # at this point we should be good to launch, these are just sanity checks that should never be reached + + #update the timestamp of the local exe if exists(InstallDir + "/" + ExecutableName): LastWrite = datetime.utcfromtimestamp( pathlib.Path(InstallDir + "/" + ExecutableName).stat().st_mtime From 7ae6e45e916ec98a7c55d2364b62e9b2dd8ca38c Mon Sep 17 00:00:00 2001 From: ZedB0T <89345505+Zedb0T@users.noreply.github.com> Date: Mon, 21 Aug 2023 10:41:28 -0400 Subject: [PATCH 06/25] Remove pycdlib --- utils/launcherUtils.py | 52 ------------------------------------------ 1 file changed, 52 deletions(-) diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index aa9e00c..aa5759d 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -23,7 +23,6 @@ from appdirs import AppDirs import platform import stat -import pycdlib from pathlib import Path import time @@ -268,57 +267,6 @@ def replaceText(path, search_text, replace_text): def ensure_dir(path): path.mkdir(parents=True, exist_ok=True) -def extract_recursive(iso, parent_iso_path, extract_dir_path): - for child in iso.list_children(iso_path=parent_iso_path): - identifier = child.file_identifier().decode() - absolute_iso_path = f'{parent_iso_path}{identifier}' - - # Skip . and .. directories - if identifier in ['.', '..']: - continue - - # Recurse directories or extract files - if child.is_dir(): - extract_recursive(iso, f'{absolute_iso_path}/', extract_dir_path / identifier) - else: - file_name = identifier.split(';')[0] - - # Strip empty file extensions (e.g. DMMY. -> DMMY) - if file_name.endswith('.'): - file_name = file_name[:-1] - - file_path = extract_dir_path / file_name - - # Ensure the parent directory exists - ensure_dir(extract_dir_path) - - # Write the output file - print(f' {absolute_iso_path}: ', end='', flush=True) - iso.get_file_from_iso(file_path, iso_path=f'{absolute_iso_path}') - print(f'DONE', flush=True) - -def extract_iso(ISO_PATH, EXTRACT_DIR): - # Clean original extraction directory - ISO_PATH = Path(ISO_PATH) - EXTRACT_DIR = Path(EXTRACT_DIR) - if EXTRACT_DIR.exists(): - shutil.rmtree(EXTRACT_DIR) - - # Create extraction directories - ensure_dir(EXTRACT_DIR) - - # Open the iso for reading - iso = pycdlib.PyCdlib() - iso.open(ISO_PATH) - - # Extract the contents of the iso - print('Extracting ISO contents', flush=True) - extract_recursive(iso, '/', EXTRACT_DIR) - - # Close the iso - iso.close() - return True - def open_browser_link(): url = "https://google.com" # Replace with the desired URL if sys.platform.startswith('linux'): From aefa58df7038636a733cf91f54359e0a23e9eed4 Mon Sep 17 00:00:00 2001 From: ZedB0T <89345505+Zedb0T@users.noreply.github.com> Date: Mon, 21 Aug 2023 10:59:50 -0400 Subject: [PATCH 07/25] Add a button to view iso_data folder --- openGOALModLauncher.py | 6 ++++++ utils/launcherUtils.py | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/openGOALModLauncher.py b/openGOALModLauncher.py index e03d033..47df72e 100644 --- a/openGOALModLauncher.py +++ b/openGOALModLauncher.py @@ -345,6 +345,9 @@ def getRefreshedTableData(sort_col_idx): [sg.Text("")], [ sg.Btn(button_text="Launch", key="-LAUNCH-", expand_x=True), + sg.Btn( + button_text="View ISO Folder", key="-VIEWISOFOLDER-", expand_x=True + ), sg.Btn( button_text="View Folder", key="-VIEWFOLDER-", expand_x=True ), @@ -585,6 +588,9 @@ def reset(): launcherUtils.openFolder(dir) else: sg.Popup("Selected mod is not installed", keep_on_top=True, icon=iconfile) + elif event == "-VIEWISOFOLDER-": + dir = dirs.user_data_dir + "\\OpenGOAL\\" + "mods\\data\\iso_data" + launcherUtils.openFolder(dir) elif event == "-REINSTALL-": tmpModName = window["-SELECTEDMODNAME-"].get() tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index aa5759d..4c6afa5 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -157,7 +157,10 @@ def launch_local(MOD_ID, GAME): def openFolder(path): + if not exists(dirs.user_data_dir + "\\OpenGOAL\\" + "mods\\data\\iso_data\\jak2"): + os.makedirs(dirs.user_data_dir + "\\OpenGOAL\\" + "mods\\data\\iso_data\\jak2") FILEBROWSER_PATH = os.path.join(os.getenv("WINDIR"), "explorer.exe") + print(path) subprocess.run([FILEBROWSER_PATH, path]) #tmpModURL, tmpModSelected, tmpModName, linkType, tmpGame @@ -492,6 +495,8 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): 1 / 0 if GAME == "jak2": #since extractor currently doesnt know about jak 2, we need to manually place the iso contents into the folder we expect + if not exists(dirs.user_data_dir + "\\OpenGOAL\\" + "mods\\data\\iso_data\\jak2"): + os.makedirs(dirs.user_data_dir + "\\OpenGOAL\\" + "mods\\data\\iso_data\\jak2") while not (exists((UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"))): print("Didnt find iso in " + UniversalIsoPath + "//" + GAME + "//" + " sleeping for 5 seconds, then checking again.") time.sleep(5) From f10aedcd9a56d7c765970919dc179ea57c604c1f Mon Sep 17 00:00:00 2001 From: ZedB0T <89345505+Zedb0T@users.noreply.github.com> Date: Mon, 21 Aug 2023 11:17:23 -0400 Subject: [PATCH 08/25] Grab decompiler if package is missing it --- utils/launcherUtils.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index 4c6afa5..52764ee 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -295,8 +295,26 @@ def open_folder(path): def divide_by_zero(): 1 / 0 + +#check if we have decompiler in the path, if not check if we have a backup, if so use it, if not download a backup then use it def getDecompiler(path): - #check if we have decompiler in the path, if not check if we have a backup, if so use it, if not download a backup then use it + # print("AHHHHHHHH") + # time.sleep(15) + decompiler_exe = "decompiler.exe" + decompiler_url = "https://github.com/OpenGOAL-Mods/OG-Mod-Base/raw/main/out/build/Release/bin/decompiler.exe" + + # Check if the decompiler exists in the provided path + if os.path.exists(os.path.join(path, decompiler_exe)): + print(f"Found {decompiler_exe} in the directory.") + return + else: + # Check if the backup decompiler exists + print(f"Couldn't find {decompiler_exe} in the directory or backup. Downloading it...") + urllib.request.urlretrieve(decompiler_url, os.path.join(path, decompiler_exe)) + print(f"{decompiler_exe} downloaded successfully as backup.") + while not os.path.exists(os.path.join(path, decompiler_exe)): + time.sleep(1) # Wait for the download to complete + return def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): From 17cd63bdd7106b2d437e35ce6ea08097d17c286f Mon Sep 17 00:00:00 2001 From: ZedB0T <89345505+Zedb0T@users.noreply.github.com> Date: Mon, 21 Aug 2023 11:57:39 -0400 Subject: [PATCH 09/25] Move iso data to OpenGOAL-Mods dir --- openGOALModLauncher.py | 2 +- utils/launcherUtils.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/openGOALModLauncher.py b/openGOALModLauncher.py index 47df72e..f7a7322 100644 --- a/openGOALModLauncher.py +++ b/openGOALModLauncher.py @@ -589,7 +589,7 @@ def reset(): else: sg.Popup("Selected mod is not installed", keep_on_top=True, icon=iconfile) elif event == "-VIEWISOFOLDER-": - dir = dirs.user_data_dir + "\\OpenGOAL\\" + "mods\\data\\iso_data" + dir = dirs.user_data_dir + "\OpenGOAL-Mods\_iso_data" launcherUtils.openFolder(dir) elif event == "-REINSTALL-": tmpModName = window["-SELECTEDMODNAME-"].get() diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index 52764ee..6f6bd58 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -127,7 +127,7 @@ def launch_local(MOD_ID, GAME): time.sleep(1) InstallDir = ModFolderPATH + MOD_ID - UniversalIsoPath = AppdataPATH + "\OpenGOAL\mods\data\iso_data" + UniversalIsoPath = AppdataPATH + "\OpenGOAL-Mods\_iso_data" GKCOMMANDLINElist = [ os.path.abspath(InstallDir + "\gk.exe"), # Using os.path.abspath to get the absolute path. @@ -167,7 +167,7 @@ def openFolder(path): def reinstall(URL, MOD_ID, MODNAME, LINKTYPE, GAME): InstallDir = ModFolderPATH + MOD_ID AppdataPATH = os.getenv("APPDATA") - UniversalIsoPath = AppdataPATH + "\OpenGOAL\mods\data\iso_data" + UniversalIsoPath = AppdataPATH + "\OpenGOAL-Mods\_iso_data" #reinstall has a lot of duplicated logic not sure if there is a reason for this yet, but for now for jak 2 we can just delte the directory then call the install/launch function if GAME == "jak2": path_to_remove = InstallDir @@ -335,7 +335,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): # paths InstallDir = ModFolderPATH + MOD_ID AppdataPATH = os.getenv("APPDATA") - UniversalIsoPath = AppdataPATH + "\OpenGOAL\mods\data\iso_data" + UniversalIsoPath = AppdataPATH + "\OpenGOAL-Mods\_iso_data" DataFolder = InstallDir + "\\data" GkPATH = InstallDir + "\gk.exe" GoalCPATH = InstallDir + "\goalc.exe" @@ -513,8 +513,8 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): 1 / 0 if GAME == "jak2": #since extractor currently doesnt know about jak 2, we need to manually place the iso contents into the folder we expect - if not exists(dirs.user_data_dir + "\\OpenGOAL\\" + "mods\\data\\iso_data\\jak2"): - os.makedirs(dirs.user_data_dir + "\\OpenGOAL\\" + "mods\\data\\iso_data\\jak2") + if not exists(UniversalIsoPath + "//" + GAME): + os.makedirs(UniversalIsoPath + "//" + GAME) while not (exists((UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"))): print("Didnt find iso in " + UniversalIsoPath + "//" + GAME + "//" + " sleeping for 5 seconds, then checking again.") time.sleep(5) From eef97dcdab55273becf9bb0ff1f00ca4fb620372 Mon Sep 17 00:00:00 2001 From: ZedB0T <89345505+Zedb0T@users.noreply.github.com> Date: Mon, 21 Aug 2023 14:31:07 -0400 Subject: [PATCH 10/25] Fix jak 1 add dev mode --- openGOALModLauncher.py | 18 ++++++++++++++++-- resources/jak1_mods.json | 3 ++- utils/launcherUtils.py | 11 ++++++++--- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/openGOALModLauncher.py b/openGOALModLauncher.py index f7a7322..d83cda1 100644 --- a/openGOALModLauncher.py +++ b/openGOALModLauncher.py @@ -81,6 +81,7 @@ def exitWithError(): currentModImage = None steamDIR = None dirs = AppDirs(roaming=True) +isdeveloper = False # C:\Users\USERNAME\AppData\Roaming\OPENGOAL-UnofficalModLauncher\ AppdataPATH = os.path.join(dirs.user_data_dir, "OPENGOAL-UnofficalModLauncher", "") @@ -89,6 +90,18 @@ def exitWithError(): # grab images from web +# set dev mode if we should +developer_substrings = { + "NinjaPC", + # Add more entries as needed +} + +for substring in developer_substrings: + if substring in AppdataPATH: + isdeveloper = True + break + + # url to splash screen image url = "https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/modlaunchersplash.png" jpg_data = ( @@ -209,12 +222,13 @@ def exitWithError(): INCLUDE_UNINSTALLED = True LATEST_TABLE_SORT = [6, False] # wakeup sorted by last launch date -mod_game = "jak2" def getRefreshedTableData(sort_col_idx): # uncomment/comment the next two lines if you want to test with a local file # mod_dict = requests.get("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/jak1_mods.json").json() mod_dict = json.loads(open("resources/jak1_mods.json", "r").read()) + if not isdeveloper: + mod_dict = {key: value for key, value in mod_dict.items() if not value.get("dev")} mod_dict = dict(sorted(mod_dict.items(), key=lambda x: x[1]["release_date"], reverse=True)) mod_table_data = [] @@ -432,7 +446,7 @@ def getRefreshedTableData(sort_col_idx): def handleModTableSelection(row): global LATEST_TABLE_DATA mod = LATEST_TABLE_DATA[row] - print(mod) + #print(mod) mod_id = mod[0] mod_name = mod[1] diff --git a/resources/jak1_mods.json b/resources/jak1_mods.json index 5f179aa..d7af2fc 100644 --- a/resources/jak1_mods.json +++ b/resources/jak1_mods.json @@ -544,6 +544,7 @@ "URL": "https://github.com/OpenGOAL-Mods/OG-Mod-Base/releases", "image_override_url": "https://cdn.discordapp.com/attachments/1007077732032721037/1139110276273287239/image.png", "website_url": "https://github.com/dallmeyer/jak-up/blob/main/README.md", - "game": "jak2" + "game": "jak2", + "dev": "true" } } diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index 6f6bd58..39402fd 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -204,19 +204,22 @@ def reinstall(URL, MOD_ID, MODNAME, LINKTYPE, GAME): iso_path = filedialog.askopenfilename() root.destroy() if pathlib.Path(iso_path).is_file: - if not (pathlib.Path(iso_path).suffix).lower() == ".iso" or not (pathlib.Path(iso_path).suffix).lower() == ".zip": + if not (pathlib.Path(iso_path).suffix).lower() == ".iso" : + print((pathlib.Path(iso_path).suffix).lower()) 1 / 0 print("Extraction completed successfully.") # Close Gk and goalc if they were open. try_kill_process("gk.exe") try_kill_process("goalc.exe") print("Done update starting extractor\n") + print(currentOS + " POOOOOOOOOOOOOOOP") if currentOS == "Windows": extractor_command_list = [ os.path.join(InstallDir, "extractor.exe"), "-f", iso_path, ] + print("os is windows using " + extractor_command_list) if currentOS == "Linux": # We need to give the executibles execute permissions in Linux but this doesn't work # chmod_command_list = ["cd" + os.path.join(LauncherDir), "chmod +x extractor goalc gk"] @@ -509,7 +512,9 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): iso_path = filedialog.askopenfilename() root.destroy() if pathlib.Path(iso_path).is_file: - if not (pathlib.Path(iso_path).suffix).lower() == ".iso" or not (pathlib.Path(iso_path).suffix).lower() == ".zip": + if not (pathlib.Path(iso_path).suffix).lower() == ".iso": + print((pathlib.Path(iso_path).suffix).lower()) + print("error code: 23984h") 1 / 0 if GAME == "jak2": #since extractor currently doesnt know about jak 2, we need to manually place the iso contents into the folder we expect @@ -575,7 +580,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): #Extract and compile if(GAME == "jak1"): extractor_command_list = [InstallDir + "\extractor.exe", "-f", iso_path , "-e", "-v", "-d", "-c"] - #print(extractor_command_list) + print(extractor_command_list) subprocess.Popen(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir)) while process_exists("extractor.exe"): print("extractor.exe still running, sleeping for 1s") From a9fcb4fd2dc8f72d6b4760bc816b950400f78921 Mon Sep 17 00:00:00 2001 From: ZedB0T <89345505+Zedb0T@users.noreply.github.com> Date: Mon, 21 Aug 2023 14:32:33 -0400 Subject: [PATCH 11/25] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 69d548b..5242b9b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ dist/* build/* .env +launcherUtilsbackup.py twitchcommands.spec resources/data/decompiler_out/* resources/data/iso_data/* From f1201983a3335da18a5cde1d55d08a6632de8138 Mon Sep 17 00:00:00 2001 From: ZedB0T <89345505+Zedb0T@users.noreply.github.com> Date: Mon, 21 Aug 2023 14:46:19 -0400 Subject: [PATCH 12/25] Fix jak 1 iso moving --- utils/launcherUtils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index 39402fd..d7afca0 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -646,8 +646,10 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): print("goalc.exe still running, sleeping for 1s") time.sleep(1) + while not (exists(InstallDir + "/data/iso_data/" + GAME + "//Z6TAIL.DUP")): + time.sleep(5) - + shutil.copytree( InstallDir + "/data/iso_data/" + GAME, UniversalIsoPath + "//" + GAME + "//") path_to_remove = InstallDir + "/data/iso_data/" + GAME if os.path.exists(path_to_remove): shutil.rmtree(path_to_remove) From 5e709d6ca3d7d86b98324341e5cc4920e1728fab Mon Sep 17 00:00:00 2001 From: ZedB0T <89345505+Zedb0T@users.noreply.github.com> Date: Mon, 21 Aug 2023 15:00:24 -0400 Subject: [PATCH 13/25] fix jak 1 for real --- utils/launcherUtils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index d7afca0..2b7fbb0 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -646,10 +646,11 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): print("goalc.exe still running, sleeping for 1s") time.sleep(1) - while not (exists(InstallDir + "/data/iso_data/" + GAME + "//Z6TAIL.DUP")): + while not (exists(InstallDir + "/data/iso_data/" + GAME + "//Z6TAIL.DUP")) and (exists(InstallDir + "/data/iso_data/" + GAME + "//")): time.sleep(5) - shutil.copytree( InstallDir + "/data/iso_data/" + GAME, UniversalIsoPath + "//" + GAME + "//") + if (exists(InstallDir + "/data/iso_data/" + GAME + "//Z6TAIL.DUP")): + shutil.copytree( InstallDir + "/data/iso_data/" + GAME, UniversalIsoPath + "//" + GAME + "//") path_to_remove = InstallDir + "/data/iso_data/" + GAME if os.path.exists(path_to_remove): shutil.rmtree(path_to_remove) From 5b8c091533bda8beda3eed7b2f4184c0a792076d Mon Sep 17 00:00:00 2001 From: Zedb0T <89345505+Zedb0T@users.noreply.github.com> Date: Wed, 23 Aug 2023 10:57:03 -0400 Subject: [PATCH 14/25] Fix file existing bug --- openGOALModLauncher.py | 1 + utils/launcherUtils.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/openGOALModLauncher.py b/openGOALModLauncher.py index d83cda1..43b94e9 100644 --- a/openGOALModLauncher.py +++ b/openGOALModLauncher.py @@ -93,6 +93,7 @@ def exitWithError(): # set dev mode if we should developer_substrings = { "NinjaPC", + "Zed" # Add more entries as needed } diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index 2b7fbb0..9fe20c9 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -649,7 +649,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): while not (exists(InstallDir + "/data/iso_data/" + GAME + "//Z6TAIL.DUP")) and (exists(InstallDir + "/data/iso_data/" + GAME + "//")): time.sleep(5) - if (exists(InstallDir + "/data/iso_data/" + GAME + "//Z6TAIL.DUP")): + if (exists(InstallDir + "/data/iso_data/" + GAME + "//Z6TAIL.DUP")) and not (exists(UniversalIsoPath + "//" + GAME + "//Z6TAIL.DUP")): shutil.copytree( InstallDir + "/data/iso_data/" + GAME, UniversalIsoPath + "//" + GAME + "//") path_to_remove = InstallDir + "/data/iso_data/" + GAME if os.path.exists(path_to_remove): From e876eac58ae5596ee028394550bbb6aa55b014f9 Mon Sep 17 00:00:00 2001 From: Zedb0T <89345505+Zedb0T@users.noreply.github.com> Date: Wed, 13 Sep 2023 18:06:23 -0400 Subject: [PATCH 15/25] address concerns --- buildlaunchercoreEXE.bat | 2 +- openGOALModLauncher.py | 46 +++++++++++++++------------------------- requirements.txt | 2 +- resources/jak1_mods.json | 7 +++--- utils/launcherUtils.py | 3 +-- 5 files changed, 23 insertions(+), 37 deletions(-) diff --git a/buildlaunchercoreEXE.bat b/buildlaunchercoreEXE.bat index 817b7dc..3f35b03 100644 --- a/buildlaunchercoreEXE.bat +++ b/buildlaunchercoreEXE.bat @@ -1,6 +1,6 @@ set mypath=%~dp0 -pyinstaller --onefile openGOALModLauncher.py --icon resources\appicon.ico --collect-data "pycdlib" --hidden-import=pycdlib datas=[(path.join(site_packages,"pycdlib")], +pyinstaller --onefile openGOALModLauncher.py --icon resources\appicon.ico , move "%mypath%dist\openGOALModLauncher.exe" "%mypath%/" RENAME "%mypath%\openGOALModLauncher.exe" "openGOALModLauncher.exe" REM @RD /S /Q "%mypath%/build" diff --git a/openGOALModLauncher.py b/openGOALModLauncher.py index 43b94e9..ef3cf1c 100644 --- a/openGOALModLauncher.py +++ b/openGOALModLauncher.py @@ -16,7 +16,7 @@ import os.path import requests import time -import datetime +from datetime import datetime import sys import webbrowser import os @@ -27,7 +27,7 @@ from appdirs import AppDirs import platform import stat - +from datetime import datetime from pathlib import Path @@ -81,7 +81,7 @@ def exitWithError(): currentModImage = None steamDIR = None dirs = AppDirs(roaming=True) -isdeveloper = False + # C:\Users\USERNAME\AppData\Roaming\OPENGOAL-UnofficalModLauncher\ AppdataPATH = os.path.join(dirs.user_data_dir, "OPENGOAL-UnofficalModLauncher", "") @@ -90,19 +90,6 @@ def exitWithError(): # grab images from web -# set dev mode if we should -developer_substrings = { - "NinjaPC", - "Zed" - # Add more entries as needed -} - -for substring in developer_substrings: - if substring in AppdataPATH: - isdeveloper = True - break - - # url to splash screen image url = "https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/modlaunchersplash.png" jpg_data = ( @@ -225,11 +212,9 @@ def exitWithError(): def getRefreshedTableData(sort_col_idx): # uncomment/comment the next two lines if you want to test with a local file - # mod_dict = requests.get("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/jak1_mods.json").json() - mod_dict = json.loads(open("resources/jak1_mods.json", "r").read()) + mod_dict = requests.get("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/jak1_mods.json").json() + #mod_dict = json.loads(open("resources/jak1_mods.json", "r").read()) - if not isdeveloper: - mod_dict = {key: value for key, value in mod_dict.items() if not value.get("dev")} mod_dict = dict(sorted(mod_dict.items(), key=lambda x: x[1]["release_date"], reverse=True)) mod_table_data = [] @@ -248,20 +233,20 @@ def getRefreshedTableData(sort_col_idx): # determine local install/access datetime if mod_id in installed_mod_subfolders: - mod["install_date"] = f"{datetime.datetime.fromtimestamp(installed_mod_subfolders[mod_id]):%Y-%m-%d %H:%M}" + mod["install_date"] = f"{datetime.fromtimestamp(installed_mod_subfolders[mod_id]):%Y-%m-%d %H:%M}" if exists(f"{ModFolderPATH}/{mod_id}/gk.exe"): gk_stat = os.stat(f"{ModFolderPATH}/{mod_id}/gk.exe") - mod["access_date"] = f"{datetime.datetime.fromtimestamp(gk_stat.st_atime):%Y-%m-%d %H:%M}" + mod["access_date"] = f"{datetime.fromtimestamp(gk_stat.st_atime):%Y-%m-%d %H:%M}" elif mod_name in installed_mod_subfolders: # previous installation using mod_name (will migrate after this step) - mod["install_date"] = f"{datetime.datetime.fromtimestamp(installed_mod_subfolders[mod_name]):%Y-%m-%d %H:%M}" + mod["install_date"] = f"{datetime.fromtimestamp(installed_mod_subfolders[mod_name]):%Y-%m-%d %H:%M}" # migrate folder to use mod_id instead of mod_name shutil.move(ModFolderPATH + "/" + mod_name, ModFolderPATH + "/" + mod_id) if exists(f"{ModFolderPATH}/{mod_id}/gk.exe"): gk_stat = os.stat(f"{ModFolderPATH}/{mod_id}/gk.exe") - mod["access_date"] = f"{datetime.datetime.fromtimestamp(gk_stat.st_atime):%Y-%m-%d %H:%M}" + mod["access_date"] = f"{datetime.fromtimestamp(gk_stat.st_atime):%Y-%m-%d %H:%M}" mod["contributors"] = ", ".join(mod["contributors"]) mod["tags"].sort() @@ -272,14 +257,15 @@ def getRefreshedTableData(sort_col_idx): # update_date = githubUtils.getLatestAvailableUpdateDatetime(mod["URL"]) # if update_date: # mod["latest_available_update_date"] = f"{update_date:%Y-%m-%d %H:%M}" - + # only add to data if passes filter (if any) if ( FILTER_STR is None - or FILTER_STR == "" - or FILTER_STR in mod_name.lower() - or FILTER_STR in mod["contributors"].lower() - or FILTER_STR in mod["tags"].lower() + or FILTER_STR == "" and mod["game"] != "jak2" + or FILTER_STR in mod_name.lower() and mod["game"] != "jak2" + or FILTER_STR in mod["contributors"].lower() and mod["game"] != "jak2" + or FILTER_STR in mod["tags"].lower() and mod["game"] != "jak2" + or FILTER_STR == "i understand this is a test and will report any bugs to jak-project on github or in the opengoal discord" and mod["game"] == "jak2" ): if (INCLUDE_INSTALLED and mod["access_date"] != "Not Installed") or ( INCLUDE_UNINSTALLED and mod["access_date"] == "Not Installed" @@ -581,6 +567,8 @@ def reset(): tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] tmpModURL = window["-SELECTEDMODNAME-"].metadata["url"] tmpGame = window["-SELECTEDMODNAME-"].metadata["game"] + if FILTER_STR == "i understand this is a test and will report any bugs to jak-project on github or in the opengoal discord": + tmpGame = "jak2" # online launch window["-LAUNCH-"].update(disabled=True) diff --git a/requirements.txt b/requirements.txt index 76bb57b..f970537 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,4 @@ Pillow progressbar cloudscraper appdirs -pycdlib + diff --git a/resources/jak1_mods.json b/resources/jak1_mods.json index d7af2fc..d3507b7 100644 --- a/resources/jak1_mods.json +++ b/resources/jak1_mods.json @@ -531,8 +531,8 @@ }, "mod_base_2": { "name": "Jak 2", - "desc": "Early test build. WARNING: the levels take up ~400MB, and will take a couple minutes to install.", - "contributors": ["barg034"], + "desc": "Early test build. Click View ISO Folder and place jak 2 iso there.", + "contributors": ["OpenGOAL"], "tags": [ "beta", "gameplay-mod", @@ -542,9 +542,8 @@ ], "release_date": "2023-08-10", "URL": "https://github.com/OpenGOAL-Mods/OG-Mod-Base/releases", - "image_override_url": "https://cdn.discordapp.com/attachments/1007077732032721037/1139110276273287239/image.png", + "image_override_url": "https://vgboxart.com/boxes/PS2/38248-jak-ii.png", "website_url": "https://github.com/dallmeyer/jak-up/blob/main/README.md", "game": "jak2", - "dev": "true" } } diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index 9fe20c9..e695035 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -212,7 +212,6 @@ def reinstall(URL, MOD_ID, MODNAME, LINKTYPE, GAME): try_kill_process("gk.exe") try_kill_process("goalc.exe") print("Done update starting extractor\n") - print(currentOS + " POOOOOOOOOOOOOOOP") if currentOS == "Windows": extractor_command_list = [ os.path.join(InstallDir, "extractor.exe"), @@ -492,7 +491,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): print("Found in " + UniversalIsoPath +"//" + GAME + "//" + "Z6TAIL.DUP") iso_path = UniversalIsoPath + "\\" + GAME else: - print("We did not find ISO data from a previous mod, lets ask for some!") + print("We did not find "+ GAME + "ISO data from a previous mod, lets ask for some!") #cleanup and remove a corrupted iso if os.path.exists(UniversalIsoPath + "//" + GAME) and os.path.isdir(UniversalIsoPath) and not (exists((UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"))): print("Removing corrupted iso destination...") From 304ebc80ffafc339d5c879c1ef8593e792159428 Mon Sep 17 00:00:00 2001 From: Zedb0T <89345505+Zedb0T@users.noreply.github.com> Date: Wed, 13 Sep 2023 23:22:16 -0400 Subject: [PATCH 16/25] Add basic threading --- openGOALModLauncher.py | 65 ++++++++++++++++++++++++++-------------- resources/jak1_mods.json | 17 +++++++++++ utils/launcherUtils.py | 65 ++++++++++++++++++++++++++-------------- 3 files changed, 102 insertions(+), 45 deletions(-) diff --git a/openGOALModLauncher.py b/openGOALModLauncher.py index ef3cf1c..a797d23 100644 --- a/openGOALModLauncher.py +++ b/openGOALModLauncher.py @@ -6,6 +6,7 @@ """ # we will clean these up later but for now leave even unused imports +import threading from PIL import Image from utils import launcherUtils, githubUtils @@ -30,7 +31,10 @@ from datetime import datetime from pathlib import Path - +def run_long_task(): + # Perform your long-running task here + # This function runs in a separate thread + pass # Replace with your task logic sg.theme("DarkBlue3") @@ -39,7 +43,26 @@ def openLauncherWebsite(): def exitWithError(): sys.exit(1) +def run_long_task(): + tmpModName = window["-SELECTEDMODNAME-"].get() + tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] + tmpModURL = window["-SELECTEDMODNAME-"].metadata["url"] + tmpGame = window["-SELECTEDMODNAME-"].metadata["game"] + if FILTER_STR == "i understand this is a test and will report any bugs to jak-project on github or in the opengoal discord": + tmpGame = "jak2" + + # online launch + window["-LAUNCH-"].update(disabled=True) + window["-LAUNCH-"].update("Updating...") + [linkType, tmpModURL] = githubUtils.identifyLinkType(tmpModURL) + launcherUtils.launch(tmpModURL, tmpModSelected, tmpModName, linkType, tmpGame) + + # refresh table in case new mod installed + reset() + # turn the button back on + window["-LAUNCH-"].update("Launch") + window["-LAUNCH-"].update(disabled=False) # Folder where script is placed, It looks in this for the Exectuable if getattr(sys, "frozen", False): # If we are a pyinstaller exe get the path of this file, not python @@ -212,8 +235,19 @@ def exitWithError(): def getRefreshedTableData(sort_col_idx): # uncomment/comment the next two lines if you want to test with a local file - mod_dict = requests.get("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/jak1_mods.json").json() - #mod_dict = json.loads(open("resources/jak1_mods.json", "r").read()) + remote_url = "https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/jak1_mods.json" + remote_mods = requests.get(remote_url).json() + + # Initialize an empty dictionary to store the combined data + mod_dict = {} + + # Load data from the local file if it exists + local_file_path = "resources/jak1_mods.json" + if os.path.exists(local_file_path): + local_mods = json.loads(open(local_file_path, "r").read()) + + # Merge the remote and local data while removing duplicates + mod_dict = {**remote_mods, **local_mods} mod_dict = dict(sorted(mod_dict.items(), key=lambda x: x[1]["release_date"], reverse=True)) @@ -563,25 +597,9 @@ def reset(): elif event == "-REFRESH-": reset() elif event == "-LAUNCH-": - tmpModName = window["-SELECTEDMODNAME-"].get() - tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] - tmpModURL = window["-SELECTEDMODNAME-"].metadata["url"] - tmpGame = window["-SELECTEDMODNAME-"].metadata["game"] - if FILTER_STR == "i understand this is a test and will report any bugs to jak-project on github or in the opengoal discord": - tmpGame = "jak2" - - # online launch - window["-LAUNCH-"].update(disabled=True) - window["-LAUNCH-"].update("Updating...") - [linkType, tmpModURL] = githubUtils.identifyLinkType(tmpModURL) - launcherUtils.launch(tmpModURL, tmpModSelected, tmpModName, linkType, tmpGame) - - # refresh table in case new mod installed - reset() - - # turn the button back on - window["-LAUNCH-"].update("Launch") - window["-LAUNCH-"].update(disabled=False) + long_task_thread = threading.Thread(target=run_long_task) + long_task_thread.start() + elif event == "-VIEWFOLDER-": tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] subfolders = [f.name for f in os.scandir(ModFolderPATH) if f.is_dir()] @@ -593,6 +611,7 @@ def reset(): sg.Popup("Selected mod is not installed", keep_on_top=True, icon=iconfile) elif event == "-VIEWISOFOLDER-": dir = dirs.user_data_dir + "\OpenGOAL-Mods\_iso_data" + launcherUtils.ensure_jak_folders_exist() launcherUtils.openFolder(dir) elif event == "-REINSTALL-": tmpModName = window["-SELECTEDMODNAME-"].get() @@ -601,7 +620,7 @@ def reset(): tmpGame = window["-SELECTEDMODNAME-"].metadata["game"] [linkType, tmpModURL] = githubUtils.identifyLinkType(tmpModURL) subfolders = [f.name for f in os.scandir(ModFolderPATH) if f.is_dir()] - +#I understand this is a test and will report any bugs to jak-project on github or in the opengoal discord if tmpModSelected in subfolders: dir = dirs.user_data_dir + "\\OpenGOAL-Mods\\" + tmpModSelected ans = sg.popup_ok_cancel( diff --git a/resources/jak1_mods.json b/resources/jak1_mods.json index 35593d8..f6d9988 100644 --- a/resources/jak1_mods.json +++ b/resources/jak1_mods.json @@ -542,6 +542,23 @@ "URL": "https://github.com/Jak-Mods/candy-pop-keira/releases", "image_override_url": "https://i.imgur.com/83xZThN.png", "website_url": "https://github.com/Jak-Mods/candy-pop-keira", + "game": "jak1" + }, + "mod_base_2": { + "name": "Jak 2", + "desc": "Early test build. WARNING: the levels take up ~400MB, and will take a couple minutes to install.", + "contributors": ["barg034"], + "tags": [ + "beta", + "gameplay-mod", + "challenge", + "custom-level", + "speedrunning" + ], + "release_date": "2023-08-10", + "URL": "https://github.com/OpenGOAL-Mods/OG-Mod-Base/releases", + "image_override_url": "https://cdn.discordapp.com/attachments/1007077732032721037/1139110276273287239/image.png", + "website_url": "https://github.com/dallmeyer/jak-up/blob/main/README.md", "game": "jak2" } } diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index 1a3bd2a..4acafe4 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -127,6 +127,28 @@ def moveDirContents(src, dest): dst_path = os.path.join(dest, f) shutil.move(src_path, dst_path) +def link_files_by_extension(source_dir, destination_dir): + # Ensure the source directory exists + if not os.path.exists(source_dir): + print(f"Source directory '{source_dir}' does not exist.") + return + + # Ensure the destination directory exists + if not os.path.exists(destination_dir): + os.makedirs(destination_dir) + + # Loop through the contents of the source directory + for filename in os.listdir(source_dir): + file_path = os.path.join(source_dir, filename) + + # Check if it's a file and its extension matches the specified extension + if os.path.isfile(file_path): + # Construct the destination path + destination_path = os.path.join(destination_dir, filename) + + # Create a symbolic link (change to shutil.copy if you want to copy instead) + os.symlink(file_path, destination_path) + print(f"Linked '{filename}' to '{destination_path}'") def launch_local(MOD_ID, GAME): try: @@ -178,6 +200,7 @@ def reinstall(URL, MOD_ID, MODNAME, LINKTYPE, GAME): InstallDir = ModFolderPATH + MOD_ID AppdataPATH = os.getenv("APPDATA") UniversalIsoPath = AppdataPATH + "\OpenGOAL-Mods\_iso_data" + ensure_jak_folders_exist() #reinstall has a lot of duplicated logic not sure if there is a reason for this yet, but for now for jak 2 we can just delte the directory then call the install/launch function if GAME == "jak2": path_to_remove = InstallDir @@ -217,8 +240,9 @@ def reinstall(URL, MOD_ID, MODNAME, LINKTYPE, GAME): 1 / 0 # symlink isodata for custom levels art group (goalc doesnt take -f flag) - if exists(UniversalIsoPath + r"\jak1\Z6TAIL.DUP"): + if exists(UniversalIsoPath + "//" + GAME +r"\Z6TAIL.DUP"): makeDirSymlink(InstallDir + "\\data\\iso_data", UniversalIsoPath) + link_files_by_extension( UniversalIsoPath + "//" + GAME + "//VAG",InstallDir + "//data//out//" + GAME + "//iso") # Close Gk and goalc if they were open. try_kill_process("gk.exe") @@ -309,6 +333,18 @@ def open_folder(path): def divide_by_zero(): 1 / 0 +def ensure_jak_folders_exist(): + directory = dirs.user_data_dir + "\OpenGOAL-Mods\_iso_data" + jak1_path = os.path.join(directory, "jak1") + jak2_path = os.path.join(directory, "jak2") + + if not os.path.exists(jak1_path): + os.makedirs(jak1_path) + print(f"Created 'jak1' folder at {jak1_path}") + + if not os.path.exists(jak2_path): + os.makedirs(jak2_path) + print(f"Created 'jak2' folder at {jak2_path}") #check if we have decompiler in the path, if not check if we have a backup, if so use it, if not download a backup then use it def getDecompiler(path): @@ -350,6 +386,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): InstallDir = ModFolderPATH + MOD_ID AppdataPATH = os.getenv("APPDATA") UniversalIsoPath = AppdataPATH + "\OpenGOAL-Mods\_iso_data" + ensure_jak_folders_exist() DataFolder = InstallDir + "\\data" GkPATH = InstallDir + "\gk.exe" GoalCPATH = InstallDir + "\goalc.exe" @@ -591,9 +628,10 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): ) # symlink isodata for custom levels art group (goalc doesnt take -f flag) - if exists(UniversalIsoPath + r"\jak1\Z6TAIL.DUP"): + if exists(UniversalIsoPath + r"" + "//" + GAME + "//" + "Z6TAIL.DUP"): makeDirSymlink(InstallDir + "/data/iso_data", UniversalIsoPath) + # if extractOnUpdate is True, check their ISO_DATA folder # Close Gk and goalc if they were open. @@ -603,7 +641,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): #Extract and compile if(GAME == "jak1"): - extractor_command_list = [InstallDir + "\extractor.exe", "-f", iso_path , "-e", "-v", "-d", "-c"] + extractor_command_list = [InstallDir + "\extractor.exe", "-e", "-v", "-d", "-c"] print(extractor_command_list) subprocess.Popen(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir)) while process_exists("extractor.exe"): @@ -643,18 +681,6 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): #print(goalc_command_list) - # move the extrated contents to the universal launchers directory for next time. - - #shutil.copytree(UniversalIsoPath + "//" + GAME + "//", InstallDir + "/data/iso_data/" + GAME) - - #should be good to move iso now - shutil.copytree(UniversalIsoPath + "//" + GAME + "//", InstallDir + "/data/iso_data/" + GAME) - - #keep checking to make sure the move is in a finished state - while not (exists(InstallDir + "/data/iso_data/" + GAME + "//Z6TAIL.DUP")): - print(InstallDir + "/data/iso_data/" + GAME + "//Z6TAIL.DUP " + "Not found yet, sleeping then checking again to make sure the install finished") - time.sleep(5) - #open GoalC to build jak2, for jak 1 extractor can handle this. print("Opening the Compiler subprocess - Sleeping for 5 seconds so it has time to initalize.") subprocess.Popen(goalc_command_list, shell=True, cwd=os.path.abspath(InstallDir)) @@ -675,13 +701,8 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): if (exists(InstallDir + "/data/iso_data/" + GAME + "//Z6TAIL.DUP")) and not (exists(UniversalIsoPath + "//" + GAME + "//Z6TAIL.DUP")): shutil.copytree( InstallDir + "/data/iso_data/" + GAME, UniversalIsoPath + "//" + GAME + "//") - path_to_remove = InstallDir + "/data/iso_data/" + GAME - if os.path.exists(path_to_remove): - shutil.rmtree(path_to_remove) - print(f"Path '{path_to_remove}' removed successfully.") - else: - print(f"Path '{path_to_remove}' does not exist.") - #print("copying " + InstallDir + "/data/iso_data/" + GAME + "to " + UniversalIsoPath ) + + # at this point we should be good to launch, these are just sanity checks that should never be reached From fc3bb8ea5d6d7169a1d1ec320ab6c89a6d4e2548 Mon Sep 17 00:00:00 2001 From: Zedb0T <89345505+Zedb0T@users.noreply.github.com> Date: Sun, 17 Sep 2023 07:10:28 -0400 Subject: [PATCH 17/25] abandonware --- Launcher with autoupdater.py | 210 ++++----- buildlaunchercoreEXE.bat | 2 +- buildlauncherupdaterexe.bat | 2 +- mainwindow.py | 142 ++++++ openGOALModLauncher.py | 67 +-- openGOALModLauncher2.py | 809 +++++++++++++++++++++++++++++++++++ openGOALModLauncher2.spec | 45 ++ utils/launcherUtils.py | 194 ++++----- 8 files changed, 1212 insertions(+), 259 deletions(-) create mode 100644 mainwindow.py create mode 100644 openGOALModLauncher2.py create mode 100644 openGOALModLauncher2.spec diff --git a/Launcher with autoupdater.py b/Launcher with autoupdater.py index 1055452..8b5fad9 100644 --- a/Launcher with autoupdater.py +++ b/Launcher with autoupdater.py @@ -1,35 +1,22 @@ -# -*- coding: utf-8 -*- -""" -Created on Mon Aug 29 20:46:07 2022 - -@author: Zed -""" -from datetime import datetime -from os.path import exists -import json +import PySimpleGUI as sg import os -import pathlib -import progressbar import requests -import shutil -import subprocess +import json import urllib +import shutil import traceback +from datetime import datetime +from os.path import exists +from pathlib import Path +import subprocess +AppdataPATH = os.getenv('APPDATA') + "\\OpenGOAL-UnofficialModLauncher\\" -pbar = None def show_progress(block_num, block_size, total_size): if total_size > 0: - global pbar - if pbar is None: - pbar = progressbar.ProgressBar(maxval=total_size) - pbar.start() - - downloaded = block_num * block_size - if downloaded < total_size: - pbar.update(downloaded) - else: - pbar.finish() - pbar = None + try: + window['progress_bar'].UpdateBar(block_num * block_size, total_size) + except Exception as e: + pass # Handle the exception if the window or element does not exist def try_remove_file(file): if exists(file): @@ -38,86 +25,117 @@ def try_remove_file(file): def try_remove_dir(dir): if exists(dir): shutil.rmtree(dir) - -def downloadNewestmod(): - - InstallDir = AppdataPATH + +def check_for_updates(): - launchUrl ="https://api.github.com/repos/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/releases" - response = requests.get(url = launchUrl, params = {'address':"yolo"}) + + launch_url = "https://api.github.com/repos/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/releases" + response = requests.get(url=launch_url, params={'address': "yolo"}) + if response is not None and response.status_code == 200: - # didnt get rate limited yay - r = json.loads(json.dumps(response.json())) - LatestRel = datetime.strptime(r[0].get("published_at").replace("T"," ").replace("Z",""),'%Y-%m-%d %H:%M:%S') - LatestRelAssetsURL = (json.loads(json.dumps(requests.get(url = r[0].get("assets_url"), params = {'address':"yolo"}).json())))[0].get("browser_download_url") + r = json.loads(json.dumps(response.json())) + latest_release = datetime.strptime(r[0].get("published_at").replace("T", " ").replace("Z", ""), + '%Y-%m-%d %H:%M:%S') + latest_release_assets_url = (json.loads( + json.dumps(requests.get(url=r[0].get("assets_url"), params={'address': "yolo"}).json())))[0].get( + "browser_download_url") else: - # fall back to some hard-coded release, surely we won't forget to update this occasionally - print("WARNING: failed to query github API, you might be rate-limited. Using default fallback release instead.") - LatestRel = datetime(2023, 7, 23) - LatestRelAssetsURL = "https://github.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/releases/download/v1.10fixoldpckernel/openGOALModLauncher.exe" + print("WARNING: Failed to query GitHub API, you might be rate-limited. Using default fallback release instead.") + latest_release = datetime(2023, 7, 23) + latest_release_assets_url = "https://github.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/releases/download/v1.10fixoldpckernel/openGOALModLauncher.exe" - LastWrite = datetime(2020, 5, 17) - if (os.path.exists(AppdataPATH + "\\OpengoalModLauncher.exe")): - LastWrite = datetime.utcfromtimestamp( pathlib.Path(AppdataPATH + "\\OpengoalModLauncher.exe").stat().st_mtime) + last_write = datetime(2020, 5, 17) + if os.path.exists(AppdataPATH + "\\OpengoalModLauncher.exe"): + last_write = datetime.utcfromtimestamp(Path(AppdataPATH + "\\OpengoalModLauncher.exe").stat().st_mtime) - #update checks + need_update = bool((last_write < latest_release)) + + window['installed_version'].update(f"Currently installed version created on: {last_write.strftime('%Y-%m-%d %H:%M:%S')}") + window['newest_version'].update(f"Newest version created on: {latest_release.strftime('%Y-%m-%d %H:%M:%S')}") + + if need_update: + window['update_status'].update("An update is available. Click 'Update' to install.") + window['update_button'].update(visible=True) + window['launch_button'].update(visible=False) + else: + window['update_status'].update("You are up to date.") + window['update_button'].update(visible=False) + window['launch_button'].update(visible=True) + +def download_newest_mod(): + AppdataPATH = os.getenv('APPDATA') + "\\OpenGOAL-UnofficialModLauncher\\" + + launch_url = "https://api.github.com/repos/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/releases" + response = requests.get(url=launch_url, params={'address': "yolo"}) + + if response is not None and response.status_code == 200: + r = json.loads(json.dumps(response.json())) + latest_release = datetime.strptime(r[0].get("published_at").replace("T", " ").replace("Z", ""), + '%Y-%m-%d %H:%M:%S') + latest_release_assets_url = (json.loads( + json.dumps(requests.get(url=r[0].get("assets_url"), params={'address': "yolo"}).json())))[0].get( + "browser_download_url") + else: + print("WARNING: Failed to query GitHub API, you might be rate-limited. Using default fallback release instead.") + latest_release = datetime(2023, 7, 23) + latest_release_assets_url = "https://github.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/releases/download/v1.10fixoldpckernel/openGOALModLauncher.exe" - needUpdate = bool((LastWrite < LatestRel)) + last_write = datetime(2020, 5, 17) + if os.path.exists(AppdataPATH + "\\OpengoalModLauncher.exe"): + last_write = datetime.utcfromtimestamp(Path(AppdataPATH + "\\OpengoalModLauncher.exe").stat().st_mtime) - print("Currently installed version created on: " + LastWrite.strftime('%Y-%m-%d %H:%M:%S')) - print("Newest version created on: " + LatestRel.strftime('%Y-%m-%d %H:%M:%S')) + need_update = bool((last_write < latest_release)) - if (needUpdate): - - #start the actual update method if needUpdate is true - print("Starting Update...") - #download update from github - # Create a new directory because it does not exist + if need_update: + window['update_status'].update("Starting Update...") try_remove_dir(AppdataPATH + "/temp") if not os.path.exists(AppdataPATH + "/temp"): - print("Creating install dir: " + AppdataPATH) os.makedirs(AppdataPATH + "/temp") - print("Downloading update from " + LatestRelAssetsURL) - file = urllib.request.urlopen(LatestRelAssetsURL) - print(file.length) - - urllib.request.urlretrieve(LatestRelAssetsURL, AppdataPATH + "/temp/OpengoalModLauncher.exe", show_progress) - print("Done downloading") - - - #delete any previous installation - print("Removing previous installation " + AppdataPATH) - try_remove_dir(InstallDir + "/data") - try_remove_file(InstallDir + "/gk.exe") - try_remove_file(InstallDir + "/goalc.exe") - try_remove_file(InstallDir + "/extractor.exe") - print("Extracting update") - TempDir = InstallDir + "/temp" - - - #delete the update archive - try_remove_file(TempDir + "/updateDATA.zip") - - SubDir = TempDir - print("Moving files from " + SubDir + " up to " + InstallDir) - allfiles = os.listdir(SubDir) - for f in allfiles: - shutil.move(SubDir + "/" + f, InstallDir + "/" + f) - try_remove_dir(TempDir) - -try: - AppdataPATH = os.getenv('APPDATA') + "\\OpenGOAL-UnofficalModLauncher\\" - print(AppdataPATH) - - if os.path.exists(AppdataPATH) == False: - print("Creating Directory " + AppdataPATH) - os.mkdir(AppdataPATH) - - - downloadNewestmod() - - subprocess.call([AppdataPATH + "OpengoalModLauncher.exe"]) -except Exception as e: - print("An unexcepted error occurred: ", e) - traceback.print_exc() \ No newline at end of file + window['update_status'].update("Downloading update from " + latest_release_assets_url) + file = urllib.request.urlopen(latest_release_assets_url) + urllib.request.urlretrieve(latest_release_assets_url, AppdataPATH + "/temp/OpengoalModLauncher.exe", show_progress) + window['update_status'].update("Done downloading") + + window['update_status'].update("Removing previous installation " + AppdataPATH) + try_remove_dir(AppdataPATH + "/data") + try_remove_file(AppdataPATH + "/gk.exe") + try_remove_file(AppdataPATH + "/goalc.exe") + try_remove_file(AppdataPATH + "/extractor.exe") + + window['update_status'].update("Extracting update") + temp_dir = AppdataPATH + "/temp" + try_remove_file(temp_dir + "/updateDATA.zip") + sub_dir = temp_dir + all_files = os.listdir(sub_dir) + for f in all_files: + shutil.move(sub_dir + "/" + f, AppdataPATH + "/" + f) + try_remove_dir(temp_dir) + window['update_status'].update("Update complete") + window['update_button'].update(visible=False) + window['launch_button'].update(visible=True) + +layout = [ + [sg.Text("OpenGOAL Mod Updater", font=("Helvetica", 16))], + [sg.Text("Installed Version:", size=(20, 1)), sg.Text("", size=(20, 1), key='installed_version')], + [sg.Text("Newest Version:", size=(20, 1)), sg.Text("", size=(20, 1), key='newest_version')], + [sg.ProgressBar(100, orientation='h', size=(20, 20), key='progress_bar')], + [sg.Text("", size=(40, 1), key='update_status')], + [sg.Button("Check for Updates"), sg.Button("Update", visible=False, key='update_button'), sg.Button("Launch", visible=False, key='launch_button'), sg.Button("Exit")] +] + +window = sg.Window("OpenGOAL Mod Updater", layout, finalize=True) + +while True: + event, values = window.read() + if event == sg.WIN_CLOSED or event == "Exit": + break + elif event == "Check for Updates": + check_for_updates() + elif event == "update_button": + download_newest_mod() + elif event == "launch_button": + window.close() + subprocess.call([ AppdataPATH + "openGOALModLauncher2.exe"]) + +window.close() diff --git a/buildlaunchercoreEXE.bat b/buildlaunchercoreEXE.bat index 3f35b03..509dea9 100644 --- a/buildlaunchercoreEXE.bat +++ b/buildlaunchercoreEXE.bat @@ -1,6 +1,6 @@ set mypath=%~dp0 -pyinstaller --onefile openGOALModLauncher.py --icon resources\appicon.ico , +pyinstaller --onefile openGOALModLauncher2.py --icon resources\appicon.ico --noconsole move "%mypath%dist\openGOALModLauncher.exe" "%mypath%/" RENAME "%mypath%\openGOALModLauncher.exe" "openGOALModLauncher.exe" REM @RD /S /Q "%mypath%/build" diff --git a/buildlauncherupdaterexe.bat b/buildlauncherupdaterexe.bat index 9d2a441..a7f64d7 100644 --- a/buildlauncherupdaterexe.bat +++ b/buildlauncherupdaterexe.bat @@ -1,6 +1,6 @@ set mypath=%~dp0 -pyinstaller --onefile "Launcher with autoupdater.py" --icon resources\appicon.ico +pyinstaller --onefile "Launcher with autoupdater.py" --icon resources\appicon.ico --noconsole move "%mypath%dist\Launcher with autoupdater.exe" "%mypath%/" @RD /S /Q "%mypath%/build" @RD /S /Q "%mypath%/dist" diff --git a/mainwindow.py b/mainwindow.py new file mode 100644 index 0000000..4ffb589 --- /dev/null +++ b/mainwindow.py @@ -0,0 +1,142 @@ +import threading + +from PIL import Image +from utils import launcherUtils, githubUtils +import PySimpleGUI as sg +import cloudscraper +import io +import json +import os.path +import requests +import time +from datetime import datetime +import sys +import webbrowser +import os +from os.path import exists +import shutil +import tkinter +from appdirs import AppDirs +from appdirs import AppDirs +import platform +import stat +from datetime import datetime +from pathlib import Path +import openGOALModLauncher2 + + +splashfile = openGOALModLauncher2.getPNGFromURL("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/modlaunchersplash.png") + +noimagefile = openGOALModLauncher2.getPNGFromURL("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/noRepoImageERROR.png") + +iconfile = openGOALModLauncher2.getPNGFromURL("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/appicon.ico") + + +layout = [ + [sg.Frame(title="", key='-SPLASHFRAME-', border_width=0, size=(972, 609), visible=True, element_justification="center", vertical_alignment="center", + layout= + [ + [sg.Image(key='-SPLASHIMAGE-', source=githubUtils.resize_image(splashfile, 970, 607), expand_y=True)] + ]) + ], + [sg.Frame(title="", key='-MAINFRAME-', border_width=0, visible=False, layout= + [ + [ + sg.Column( + [ + [ + sg.Text( + "", + key="-SELECTEDMODNAME-", + font=("Helvetica", 13), + metadata={"id": "", "url": ""}, + ) + ], + [sg.Text("", key="-SELECTEDMODDESC-", size=(55, 7))], + [sg.Text("Tags:", key="-SELECTEDMODTAGS-")], + [sg.Text("Contributors:", key="-SELECTEDMODCONTRIBUTORS-")], + [sg.Text("")], + [ + sg.Btn(button_text="Launch", key="-LAUNCH-", expand_x=True), + sg.Btn( + button_text="View ISO Folder", key="-VIEWISOFOLDER-", expand_x=True + ), + sg.Btn( + button_text="View Folder", key="-VIEWFOLDER-", expand_x=True + ), + sg.Btn(button_text="Reinstall", key="-REINSTALL-", expand_x=True), + sg.Btn(button_text="Uninstall", key="-UNINSTALL-", expand_x=True), + ], + [ + sg.Btn( + button_text="Website", + key="-WEBSITE-", + expand_x=True, + metadata={"url": ""}, + ), + sg.Btn( + button_text="Video(s)", + key="-VIDEOS-", + expand_x=True, + metadata={"url": ""}, + ), + sg.Btn( + button_text="Photo(s)", + key="-PHOTOS-", + expand_x=True, + metadata={"url": ""}, + ), + ], + ], + size=(400, 300), + expand_x=True, + expand_y=True, + ), + sg.Frame( + title="", + element_justification="center", + vertical_alignment="center", + border_width=0, + layout=[[sg.Image(key="-SELECTEDMODIMAGE-", expand_y=True)]], + size=(500, 300), + ), + ], + [sg.HorizontalSeparator()], + [ + sg.Text("Search"), + sg.Input(expand_x=True, enable_events=True, key="-FILTER-"), + sg.Checkbox( + text="Show Installed", + default=True, + enable_events=True, + key="-SHOWINSTALLED-", + ), + sg.Checkbox( + text="Show Uninstalled", + default=True, + enable_events=True, + key="-SHOWUNINSTALLED-", + ), + ], + [ + sg.Table( + values=LATEST_TABLE_DATA, + headings=table_headings, + visible_column_map=col_vis, + col_widths=col_width, + auto_size_columns=False, + num_rows=15, + text_color="black", + background_color="lightblue", + alternating_row_color="white", + justification="left", + selected_row_colors="black on yellow", + key="-MODTABLE-", + expand_x=True, + expand_y=True, + enable_click_events=True, + ) + ], + ]) + ] +] \ No newline at end of file diff --git a/openGOALModLauncher.py b/openGOALModLauncher.py index a797d23..36e8fec 100644 --- a/openGOALModLauncher.py +++ b/openGOALModLauncher.py @@ -31,10 +31,7 @@ from datetime import datetime from pathlib import Path -def run_long_task(): - # Perform your long-running task here - # This function runs in a separate thread - pass # Replace with your task logic + sg.theme("DarkBlue3") @@ -43,26 +40,7 @@ def openLauncherWebsite(): def exitWithError(): sys.exit(1) -def run_long_task(): - tmpModName = window["-SELECTEDMODNAME-"].get() - tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] - tmpModURL = window["-SELECTEDMODNAME-"].metadata["url"] - tmpGame = window["-SELECTEDMODNAME-"].metadata["game"] - if FILTER_STR == "i understand this is a test and will report any bugs to jak-project on github or in the opengoal discord": - tmpGame = "jak2" - - # online launch - window["-LAUNCH-"].update(disabled=True) - window["-LAUNCH-"].update("Updating...") - [linkType, tmpModURL] = githubUtils.identifyLinkType(tmpModURL) - launcherUtils.launch(tmpModURL, tmpModSelected, tmpModName, linkType, tmpGame) - - # refresh table in case new mod installed - reset() - # turn the button back on - window["-LAUNCH-"].update("Launch") - window["-LAUNCH-"].update(disabled=False) # Folder where script is placed, It looks in this for the Exectuable if getattr(sys, "frozen", False): # If we are a pyinstaller exe get the path of this file, not python @@ -98,11 +76,7 @@ def run_long_task(): installpath = str(LauncherDir + "\\resources\\") # intialize default variables so they are never null -currentModderSelected = None -currentModSelected = None -currentModURL = None -currentModImage = None -steamDIR = None + dirs = AppDirs(roaming=True) # C:\Users\USERNAME\AppData\Roaming\OPENGOAL-UnofficalModLauncher\ @@ -235,19 +209,8 @@ def run_long_task(): def getRefreshedTableData(sort_col_idx): # uncomment/comment the next two lines if you want to test with a local file - remote_url = "https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/jak1_mods.json" - remote_mods = requests.get(remote_url).json() - - # Initialize an empty dictionary to store the combined data - mod_dict = {} - - # Load data from the local file if it exists - local_file_path = "resources/jak1_mods.json" - if os.path.exists(local_file_path): - local_mods = json.loads(open(local_file_path, "r").read()) - - # Merge the remote and local data while removing duplicates - mod_dict = {**remote_mods, **local_mods} + #mod_dict = requests.get("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/jak1_mods.json").json() + mod_dict = json.loads(open("resources/jak1_mods.json", "r").read()) mod_dict = dict(sorted(mod_dict.items(), key=lambda x: x[1]["release_date"], reverse=True)) @@ -597,9 +560,25 @@ def reset(): elif event == "-REFRESH-": reset() elif event == "-LAUNCH-": - long_task_thread = threading.Thread(target=run_long_task) - long_task_thread.start() - + tmpModName = window["-SELECTEDMODNAME-"].get() + tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] + tmpModURL = window["-SELECTEDMODNAME-"].metadata["url"] + tmpGame = window["-SELECTEDMODNAME-"].metadata["game"] + if FILTER_STR == "i understand this is a test and will report any bugs to jak-project on github or in the opengoal discord": + tmpGame = "jak2" + + # online launch + window["-LAUNCH-"].update(disabled=True) + window["-LAUNCH-"].update("Updating...") + [linkType, tmpModURL] = githubUtils.identifyLinkType(tmpModURL) + launcherUtils.launch(tmpModURL, tmpModSelected, tmpModName, linkType, tmpGame) + + # refresh table in case new mod installed + reset() + + # turn the button back on + window["-LAUNCH-"].update("Launch") + window["-LAUNCH-"].update(disabled=False) elif event == "-VIEWFOLDER-": tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] subfolders = [f.name for f in os.scandir(ModFolderPATH) if f.is_dir()] diff --git a/openGOALModLauncher2.py b/openGOALModLauncher2.py new file mode 100644 index 0000000..144884f --- /dev/null +++ b/openGOALModLauncher2.py @@ -0,0 +1,809 @@ +# -*- coding: utf-8 -*- +""" +Created on Thu Aug 25 18:33:45 2022 + +@author: Zed +""" + +# we will clean these up later but for now leave even unused imports +import threading + +from PIL import Image +from utils import launcherUtils, githubUtils +import PySimpleGUI as sg +import cloudscraper +import io +import json +import os.path +import requests +import time +from datetime import datetime +import sys +import webbrowser +import os +from os.path import exists +import shutil +import tkinter +from appdirs import AppDirs +from appdirs import AppDirs +import platform +import stat +from datetime import datetime +from pathlib import Path +import queue # Import the queue modul + + + +sg.theme("DarkBlue3") + +def openLauncherWebsite(): + webbrowser.open("https://opengoal-unofficial-mods.github.io/") + +def exitWithError(): + sys.exit(1) + +def getPNGFromURL(URL): + result = None # Initialize the result variable + + def fetch_image(url): # Accept the URL parameter + nonlocal result # Access the result variable in the outer scope + jpg_data = ( + cloudscraper.create_scraper( + browser={"browser": "firefox", "platform": "windows", "mobile": False} + ) + .get(url) # Use the provided URL parameter + .content + ) + + pil_image = Image.open(io.BytesIO(jpg_data)) + png_bio = io.BytesIO() + pil_image.save(png_bio, format="PNG") + result = png_bio.getvalue() # Store the fetched image in the result variable + + thread = threading.Thread(target=fetch_image, args=(URL,)) # Pass the URL as an argument + thread.start() + thread.join() # Wait for the thread to finish + + return result # Return the fetched image data + + + +# Folder where script is placed, It looks in this for the Exectuable +if getattr(sys, "frozen", False): + # If we are a pyinstaller exe get the path of this file, not python + LauncherDir = os.path.dirname(os.path.realpath(sys.executable)) + + # Detect if a user has downloaded a release directly, if so point them to the autoupdater + if LauncherDir != os.getenv("APPDATA") + "\\OpenGOAL-UnofficalModLauncher" and os.getlogin() != "NinjaPC": + # Creating the tkinter window + root = tkinter.Tk() + root.winfo_toplevel().title("Error") + root.title = "test" + root.geometry("700x150") + message = tkinter.Label( + root, + text="Launcher not installed properly! \n Please download from: \n https://opengoal-unofficial-mods.github.io/", + ) + message.config(font=("Courier", 14)) + message.pack() + + website_button = tkinter.Button(root, text="Visit Website", command=openLauncherWebsite) + website_button.pack() + + # Button for closing + + exit_button = tkinter.Button(root, text="Exit", command=exitWithError) + exit_button.pack() + + root.mainloop() +elif __file__: + # if we are running the .py directly use this path + LauncherDir = os.path.dirname(__file__) + +installpath = str(LauncherDir + "\\resources\\") + +# intialize default variables so they are never null + +dirs = AppDirs(roaming=True) + +# C:\Users\USERNAME\AppData\Roaming\OPENGOAL-UnofficalModLauncher\ +AppdataPATH = os.path.join(dirs.user_data_dir, "OPENGOAL-UnofficalModLauncher", "") + +# C:\Users\USERNAME\AppData\Roaming\OpenGOAL-Mods\ +ModFolderPATH = os.path.join(dirs.user_data_dir, "OpenGOAL-Mods", "") + +#spawn thread to get splash file + +splashfile = getPNGFromURL("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/modlaunchersplash.png") + +noimagefile = getPNGFromURL("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/noRepoImageERROR.png") + +iconfile = getPNGFromURL("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/appicon.ico") + +loadingimage = getPNGFromURL("https://cdn.discordapp.com/attachments/1012837220664750172/1151746308000989184/image.png") + +#make the modfolderpath if first install +if not os.path.exists(ModFolderPATH): + os.makedirs(ModFolderPATH) + +table_headings = [ + "id", + "Name", + "Description", + "Tags", + "Contributors", + "Install Date", + "Last Launched", + # "Latest Update Date", + "URL", + "website_url", + "videos_url", + "photos_url", +] + +sorted_table_headings = [ + "id", + "Name", + "Description", + "Tags", + "Contributors", + "Install Date", + "Last Launched", + # "Latest Update Date", + "URL", + "website_url", + "videos_url", + "photos_url", +] + +col_vis = [ + False, + True, + False, + True, + True, + False, + True, + # True, + False, + False, + False, + False, +] + +vis_col_map = [ + 1, # name + 3, # tags + 4, # contributors + 6, # launch date +] + +col_width = [ + 0, # id + 40, # name + 0, # desc + 25, # tags + 25, # contributors + 0, # install date + 15, # launch date + 0, # url + 0, # website + 0, # videos + 0, # photos +] + +FILTER_STR = "" +INCLUDE_INSTALLED = True +INCLUDE_UNINSTALLED = True +LATEST_TABLE_SORT = [6, False] # wakeup sorted by last launch date + +def getRefreshedTableData(sort_col_idx): + + # Load data from the local file if it exists + local_file_path = "resources/jak1_mods.json" + if os.path.exists(local_file_path): + local_mods = json.loads(open(local_file_path, "r").read()) + # Load data from the remote URL + remote_url = "https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/jak1_mods.json" + remote_mods = requests.get(remote_url).json() + + # Initialize an empty dictionary to store the combined data + mod_dict = {} + + if os.path.exists(local_file_path): + # Merge the remote and local data while removing duplicates + mod_dict = {**remote_mods, **local_mods} + + mod_dict = dict(sorted(mod_dict.items(), key=lambda x: x[1]["release_date"], reverse=True)) + + mod_table_data = [] + installed_mod_subfolders = { + f.name: f.stat().st_mtime for f in os.scandir(ModFolderPATH) if f.is_dir() + } + + for mod_id in mod_dict: + + mod = mod_dict[mod_id] + mod_name = mod["name"] + + mod["install_date"] = "Not Installed" + mod["access_date"] = "Not Installed" + + # determine local install/access datetime + if mod_id in installed_mod_subfolders: + mod["install_date"] = f"{datetime.fromtimestamp(installed_mod_subfolders[mod_id]):%Y-%m-%d %H:%M}" + + if exists(f"{ModFolderPATH}/{mod_id}/gk.exe"): + gk_stat = os.stat(f"{ModFolderPATH}/{mod_id}/gk.exe") + mod["access_date"] = f"{datetime.fromtimestamp(gk_stat.st_atime):%Y-%m-%d %H:%M}" + elif mod_name in installed_mod_subfolders: + # previous installation using mod_name (will migrate after this step) + mod["install_date"] = f"{datetime.fromtimestamp(installed_mod_subfolders[mod_name]):%Y-%m-%d %H:%M}" + # migrate folder to use mod_id instead of mod_name + shutil.move(ModFolderPATH + "/" + mod_name, ModFolderPATH + "/" + mod_id) + + if exists(f"{ModFolderPATH}/{mod_id}/gk.exe"): + gk_stat = os.stat(f"{ModFolderPATH}/{mod_id}/gk.exe") + mod["access_date"] = f"{datetime.fromtimestamp(gk_stat.st_atime):%Y-%m-%d %H:%M}" + + mod["contributors"] = ", ".join(mod["contributors"]) + mod["tags"].sort() + mod["tags"] = ", ".join(mod["tags"]) + + # determine latest available update datetime - disabled as too easy to get rate-limited by github (can we do in bulk maybe?) + # mod["latest_available_update_date"] = "1900-01-01 00:00" + # update_date = githubUtils.getLatestAvailableUpdateDatetime(mod["URL"]) + # if update_date: + # mod["latest_available_update_date"] = f"{update_date:%Y-%m-%d %H:%M}" + + # only add to data if passes filter (if any) + if ( + FILTER_STR is None + or FILTER_STR == "" and mod["game"] != "jak2" + or FILTER_STR in mod_name.lower() and mod["game"] != "jak2" + or FILTER_STR in mod["contributors"].lower() and mod["game"] != "jak2" + or FILTER_STR in mod["tags"].lower() and mod["game"] != "jak2" + or FILTER_STR == "i understand this is a test and will report any bugs to jak-project on github or in the opengoal discord" and mod["game"] == "jak2" + ): + if (INCLUDE_INSTALLED and mod["access_date"] != "Not Installed") or ( + INCLUDE_UNINSTALLED and mod["access_date"] == "Not Installed" + ): + mod_table_data.append( + [ + mod_id, + mod_name, + mod["desc"], + mod["tags"], + mod["contributors"], + mod["install_date"], + mod["access_date"], + # mod["latest_available_update_date"], + mod["URL"], + (mod["website_url"] if "website_url" in mod else ""), + (mod["videos_url"] if "videos_url" in mod else ""), + (mod["photos_url"] if "photos_url" in mod else ""), + (mod["image_override_url"] if "image_override_url" in mod else ""), + (mod["game"] if "game" in mod else "") + ] + ) + if sort_col_idx is None: + # not from a heading click, retain sorting + remapped_col_idx = LATEST_TABLE_SORT[0] + else: + # heading click, adjust sorting + remapped_col_idx = vis_col_map[sort_col_idx] + + if remapped_col_idx == LATEST_TABLE_SORT[0]: + LATEST_TABLE_SORT[1] = not LATEST_TABLE_SORT[1] # same column, flip asc/desc + else: + LATEST_TABLE_SORT[0] = remapped_col_idx + LATEST_TABLE_SORT[1] = True + + global sorted_table_headings, table_headings + sorted_table_headings = table_headings.copy() + sorted_table_headings[remapped_col_idx] += (" ↑" if LATEST_TABLE_SORT[1] else " ↓") + + if remapped_col_idx == 5 or remapped_col_idx == 6: # special sort for install/access date + mod_table_data.sort(key=lambda x: "0" if x[remapped_col_idx] == "Not Installed" else x[remapped_col_idx].lower()) + else: + mod_table_data.sort(key=lambda x: x[remapped_col_idx].lower()) + + if not LATEST_TABLE_SORT[1]: + mod_table_data.reverse() + + # print(mod_table_data) + return mod_table_data + +LATEST_TABLE_DATA = [] + +# ----- Full layout ----- +layout = [ +[sg.Frame( + title="", + key='-SPLASHFRAME-', + border_width=0, # Set border_width to 0 + visible=True, + element_justification="center", + vertical_alignment="center", + layout=[ + [sg.Image( + key='-SPLASHIMAGE-', + source=githubUtils.resize_image(splashfile, 970, 607), + pad=(0, 0), # Set padding to 0 + expand_x=True, + expand_y=True + )] + ] +)], +[sg.Frame( + title="", + key='-LOADINGFRAME-', + border_width=0, # Set border_width to 0 + visible=False, + element_justification="center", + vertical_alignment="center", + layout=[ + [sg.Image( + key='-LOADINGIMAGE-', + source=githubUtils.resize_image(loadingimage, 970, 607), + pad=(0, 0), # Set padding to 0 + expand_x=True, + expand_y=True, + )] + ] +)], + + [sg.Frame( + title="", + key='-MAINFRAME-', + border_width=0, + visible=False, + layout=[ + [ + sg.Column( + [ + [sg.Text( + "", + key="-SELECTEDMODNAME-", + font=("Helvetica", 13), + metadata={"id": "", "url": ""}, + )], + [sg.Text("", key="-SELECTEDMODDESC-", size=(55, 7))], + [sg.Text("Tags:", key="-SELECTEDMODTAGS-")], + [sg.Text("Contributors:", key="-SELECTEDMODCONTRIBUTORS-")], + [sg.Text("")], + [ + sg.Btn(button_text="Launch", key="-LAUNCH-", expand_x=True), + sg.Btn( + button_text="View ISO Folder", + key="-VIEWISOFOLDER-", + expand_x=True + ), + sg.Btn( + button_text="View Folder", + key="-VIEWFOLDER-", + expand_x=True + ), + sg.Btn( + button_text="Reinstall", + key="-REINSTALL-", + expand_x=True + ), + sg.Btn( + button_text="Uninstall", + key="-UNINSTALL-", + expand_x=True + ), + ], + [ + sg.Btn( + button_text="Website", + key="-WEBSITE-", + expand_x=True, + metadata={"url": ""}, + ), + sg.Btn( + button_text="Video(s)", + key="-VIDEOS-", + expand_x=True, + metadata={"url": ""}, + ), + sg.Btn( + button_text="Photo(s)", + key="-PHOTOS-", + expand_x=True, + metadata={"url": ""}, + ), + ], + ], + size=(400, 300), + expand_x=True, + expand_y=True, + ), + sg.Frame( + title="", + element_justification="center", + vertical_alignment="center", + border_width=0, + layout=[[sg.Image(key="-SELECTEDMODIMAGE-", expand_x=True, expand_y=True)]], + size=(500, 300), + ), + ], + [sg.HorizontalSeparator()], + [ + sg.Text("Search"), + sg.Input(expand_x=True, enable_events=True, key="-FILTER-"), + sg.Checkbox( + text="Show Installed", + default=True, + enable_events=True, + key="-SHOWINSTALLED-", + ), + sg.Checkbox( + text="Show Uninstalled", + default=True, + enable_events=True, + key="-SHOWUNINSTALLED-", + ), + ], + [ + sg.Table( + values=LATEST_TABLE_DATA, + headings=table_headings, + visible_column_map=col_vis, + col_widths=col_width, + auto_size_columns=False, + num_rows=15, + text_color="black", + background_color="lightblue", + alternating_row_color="white", + justification="left", + selected_row_colors="black on yellow", + key="-MODTABLE-", + expand_x=True, + expand_y=True, + enable_click_events=True, + ) + ], + ] + )] +] + + + + +window = sg.Window("OpenGOAL Mod Launcher", layout, icon=iconfile, border_depth=0,finalize=True) + +# this is the main event loop where we handle user input + +UPDATE_UI_EVENT = "-UPDATE-UI-" +ui_update_queue = queue.Queue() + +def handleModTableSelection(row): + global LATEST_TABLE_DATA + mod = LATEST_TABLE_DATA[row] + #print(mod) + + mod_id = mod[0] + mod_name = mod[1] + mod_desc = mod[2] + mod_tags = mod[3] + mod_contributors = mod[4] + mod_install_date = mod[5] + mod_access_date = mod[6] + mod_url = mod[7] + mod_website_url = mod[8] + mod_videos_url = mod[9] + mod_photos_url = mod[10] + mod_image_override_url = mod[11] + mod_game = mod[12] + + # load mod image + try: + mod_image_url = mod_image_override_url if mod_image_override_url != "" else githubUtils.returnModImageURL(mod_url) + r = requests.head(mod_image_url).status_code + if r == 200: + jpg_data = ( + cloudscraper.create_scraper( + browser={ + "browser": "firefox", + "platform": "windows", + "mobile": False, + } + ) + .get(mod_image_url) + .content + ) + + pil_image = Image.open(io.BytesIO(jpg_data)) + png_bio = io.BytesIO() + pil_image.save(png_bio, format="PNG") + png_data = png_bio.getvalue() + window["-SELECTEDMODIMAGE-"].update(githubUtils.resize_image(png_data, 500.0, 300.0)) + # prints the int of the status code. Find more at httpstatusrappers.com :) + else: + window["-SELECTEDMODIMAGE-"].update(githubUtils.resize_image(noimagefile, 500.0, 300.0)) + except: + window["-SELECTEDMODIMAGE-"].update(githubUtils.resize_image(noimagefile, 500.0, 300.0)) + # Create a dictionary with the data to update + update_data = { + "mod_name": mod_name, + "mod_desc": mod_desc, + "mod_tags": mod_tags, + "mod_contributors": mod_contributors, + "mod_access_date": mod_access_date, + "mod_website_url": mod_website_url, + "mod_videos_url": mod_videos_url, + "mod_photos_url": mod_photos_url, + "mod_image_override_url": mod_image_override_url, + "rowidx" : row, + # ... Include other data you want to update ... + } + + # Send an event to update the UI in the main thread + ui_update_queue.put(update_data) + window.write_event_value("-UPDATE-UI-", "Your update data here") + + +windowstatus = "main" + + +launch_finished_event = threading.Event() +def launch_mod(tmpModURL): + [linkType, tmpModURL] = githubUtils.identifyLinkType(tmpModURL) + + launcherUtils.launch(tmpModURL, tmpModSelected, tmpModName, linkType, tmpGame) + launch_finished_event.set() + + + + +def run_handle_mod_table_selection(row): + mod_selection_thread = threading.Thread(target=handleModTableSelection, args=(row,)) + mod_selection_thread.start() + +def reset(): + global LATEST_TABLE_DATA + LATEST_TABLE_DATA = getRefreshedTableData(None) + window["-MODTABLE-"].update(values=LATEST_TABLE_DATA) + for i in range(len(sorted_table_headings)): + window["-MODTABLE-"].Widget.heading(i, text=sorted_table_headings[i]) + window["-MODTABLE-"].update(select_rows=[0]) + handleModTableSelection(0) + +resetThread = threading.Thread(target=reset) +resetThread.start() + + +#reset() + +bootstart = time.time() + + + +while True: + + + if windowstatus == "main" and window["-LOADINGFRAME-"].visible: + + # turn the button back on + window["-LAUNCH-"].update("Launch") + window["-LAUNCH-"].update(disabled=False) + + #We are done installing show the main menu again + window["-MAINFRAME-"].update(visible=True) + window["-MAINFRAME-"].unhide_row() + window["-LOADINGFRAME-"].update(visible=False) + window["-LOADINGFRAME-"].hide_row() + + # refresh table in case a new mod is installed + reset() + event, values = window.read(timeout=100) + + + + if event == "Exit" or event == sg.WIN_CLOSED: + break + + try: + if event == UPDATE_UI_EVENT: + # Update the UI based on the data received from the secondary thread + + update_data = ui_update_queue.get_nowait() + mod = LATEST_TABLE_DATA[update_data["rowidx"]] + mod_id = mod[0] + mod_name = mod[1] + mod_desc = mod[2] + mod_tags = mod[3] + mod_contributors = mod[4] + mod_install_date = mod[5] + mod_access_date = mod[6] + mod_url = mod[7] + mod_website_url = mod[8] + mod_videos_url = mod[9] + mod_photos_url = mod[10] + mod_image_override_url = mod[11] + mod_game = mod[12] + update_data = values + mod_name = update_data["mod_name"] + mod_desc = update_data["mod_desc"] + mod_tags = update_data["mod_tags"] + mod_contributors = update_data["mod_contributors"] + mod_access_date = update_data["mod_access_date"] + mod_website_url = update_data["mod_website_url"] + mod_videos_url = update_data["mod_videos_url"] + mod_photos_url = update_data["mod_photos_url"] + mod_image_override_url = update_data["mod_image_override_url"] + + # Update the UI elements here... + window["-LAUNCH-"].update( + "Install" if mod_access_date == "Not Installed" else "Launch" + ) + window["-SELECTEDMODNAME-"].update(mod_name) + window["-SELECTEDMODNAME-"].metadata["id"] = mod_id + window["-SELECTEDMODNAME-"].metadata["url"] = mod_url + window["-SELECTEDMODNAME-"].metadata["image_override_url"] = mod_image_override_url + + + window["-SELECTEDMODNAME-"].metadata["game"] = mod_game + + + window["-WEBSITE-"].metadata["url"] = mod_website_url + + window["-VIDEOS-"].metadata["url"] = mod_videos_url + + window["-PHOTOS-"].metadata["url"] = mod_photos_url + # ... Update other UI elements ... + except queue.Empty: + pass # No data in the queue, continue processing other events + # Handle other events and user interactions as needed + # ... + + if event == "__TIMEOUT__": + if bootstart is not None: + curtime = time.time() + if curtime - bootstart > 3: + # switch from splash screen to main screen after 3s + bootstart = None + window["-MAINFRAME-"].update(visible=True) + window["-MAINFRAME-"].unhide_row() + window["-SPLASHFRAME-"].update(visible=False) + window["-SPLASHFRAME-"].hide_row() + window.refresh() + # print("SIZE:", window.size) + elif isinstance(event, tuple): + if event[0] == "-MODTABLE-": + row = event[2][0] + col = event[2][1] + if row == None: + # empty row, do nothing + continue + elif row == -1: + # heading row, sort by col + LATEST_TABLE_DATA = getRefreshedTableData(col) + window["-MODTABLE-"].update(values=LATEST_TABLE_DATA) + for i in range(len(sorted_table_headings)): + window["-MODTABLE-"].Widget.heading(i, text=sorted_table_headings[i]) + else: + # data row, mod selected + run_handle_mod_table_selection(row) + elif event == "-FILTER-": + FILTER_STR = values["-FILTER-"].lower() + LATEST_TABLE_DATA = getRefreshedTableData(None) + window["-MODTABLE-"].update(values=LATEST_TABLE_DATA) + elif event == "-SHOWINSTALLED-": + INCLUDE_INSTALLED = window["-SHOWINSTALLED-"].get() + LATEST_TABLE_DATA = getRefreshedTableData(None) + window["-MODTABLE-"].update(values=LATEST_TABLE_DATA) + elif event == "-SHOWUNINSTALLED-": + INCLUDE_UNINSTALLED = window["-SHOWUNINSTALLED-"].get() + LATEST_TABLE_DATA = getRefreshedTableData(None) + window["-MODTABLE-"].update(values=LATEST_TABLE_DATA) + elif event == "-REFRESH-": + reset() + + elif event == "-LAUNCH-": + windowstatus = "launching" + #hide all the buttons and display a window showing that it is installing + window["-LOADINGFRAME-"].update(visible=True) + window["-LOADINGFRAME-"].unhide_row() + window["-MAINFRAME-"].update(visible=False) + window["-MAINFRAME-"].hide_row() + window.refresh() + + tmpModName = window["-SELECTEDMODNAME-"].get() + tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] + tmpModURL = window["-SELECTEDMODNAME-"].metadata["url"] + tmpGame = window["-SELECTEDMODNAME-"].metadata["game"] + if FILTER_STR == "i understand this is a test and will report any bugs to jak-project on github or in the opengoal discord": + tmpGame = "jak2" + + # online launch + window["-LAUNCH-"].update(disabled=True) + window["-LAUNCH-"].update("Updating...") + launch_thread = threading.Thread(target=launch_mod, args=(tmpModURL,)) + launch_thread.start() + #launch_thread.join() + + # Continue processing events while the background thread runs + while not launch_finished_event.is_set(): + event, values = window.read(timeout=100) + + if event == "Exit" or event == sg.WIN_CLOSED: + break + + # Handle other events here... + + # Reset windowstatus back to "main" + windowstatus = "main" + + reset() + elif event == "-VIEWFOLDER-": + tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] + subfolders = [f.name for f in os.scandir(ModFolderPATH) if f.is_dir()] + + if tmpModSelected in subfolders: + dir = dirs.user_data_dir + "\\OpenGOAL-Mods\\" + tmpModSelected + launcherUtils.openFolder(dir) + else: + sg.Popup("Selected mod is not installed", keep_on_top=True, icon=iconfile) + elif event == "-VIEWISOFOLDER-": + dir = dirs.user_data_dir + "\OpenGOAL-Mods\_iso_data" + launcherUtils.ensure_jak_folders_exist() + launcherUtils.openFolder(dir) + elif event == "-REINSTALL-": + tmpModName = window["-SELECTEDMODNAME-"].get() + tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] + tmpModURL = window["-SELECTEDMODNAME-"].metadata["url"] + tmpGame = window["-SELECTEDMODNAME-"].metadata["game"] + [linkType, tmpModURL] = githubUtils.identifyLinkType(tmpModURL) + subfolders = [f.name for f in os.scandir(ModFolderPATH) if f.is_dir()] +#I understand this is a test and will report any bugs to jak-project on github or in the opengoal discord + if tmpModSelected in subfolders: + dir = dirs.user_data_dir + "\\OpenGOAL-Mods\\" + tmpModSelected + ans = sg.popup_ok_cancel( + "Confirm: reinstalling " + + dir + + " \n\nNote: this will re-extract texture_replacements too", + icon=iconfile, + ) + if ans == "OK": + launcherUtils.reinstall(tmpModURL, tmpModSelected, tmpModName, linkType, tmpGame) + reset() + else: + sg.Popup("Selected mod is not installed", keep_on_top=True, icon=iconfile) + elif event == "-UNINSTALL-": + tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] + subfolders = [f.name for f in os.scandir(ModFolderPATH) if f.is_dir()] + + if tmpModSelected in subfolders: + dir = dirs.user_data_dir + "\\OpenGOAL-Mods\\" + tmpModSelected + ans = sg.popup_ok_cancel("Confirm: uninstalling " + dir, icon=iconfile) + if ans == "OK": + launcherUtils.try_remove_dir(dir) + reset() + sg.popup("Uninstalled " + tmpModSelected, icon=iconfile) + else: + sg.Popup("Selected mod is not installed", keep_on_top=True, icon=iconfile) + elif event == "-WEBSITE-": + window = window.refresh() + url = window["-WEBSITE-"].metadata["url"] + if url: + webbrowser.open(url) + elif event == "-VIDEOS-": + window = window.refresh() + url = window["-VIDEOS-"].metadata["url"] + if url: + webbrowser.open(url) + elif event == "-PHOTOS-": + window = window.refresh() + url = window["-PHOTOS-"].metadata["url"] + if url: + webbrowser.open(url) + else: + print("unhandled event:", event, values) + +window.close() + +#join threads +resetThread.join() \ No newline at end of file diff --git a/openGOALModLauncher2.spec b/openGOALModLauncher2.spec new file mode 100644 index 0000000..9ec8d67 --- /dev/null +++ b/openGOALModLauncher2.spec @@ -0,0 +1,45 @@ +# -*- mode: python ; coding: utf-8 -*- + + +block_cipher = None + + +a = Analysis( + ['openGOALModLauncher2.py'], + pathex=[], + binaries=[], + datas=[], + hiddenimports=[], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False, +) +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + [], + name='openGOALModLauncher2', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=False, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, + icon='resources\\appicon.ico', +) diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index 4acafe4..2155948 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -25,6 +25,8 @@ import stat from pathlib import Path import time +import win32file +import ctypes EXTRACT_ON_UPDATE = "true" FILE_DATE_TO_CHECK = "gk.exe" @@ -52,8 +54,10 @@ pbar = None -def makeDirSymlink(link, target): - subprocess.check_call('mklink /J "%s" "%s"' % (link, target), shell=True) + + + + def installedlist(PATH): @@ -120,6 +124,8 @@ def local_mod_image(MOD_ID): return path return None + + def moveDirContents(src, dest): # moves all files from src to dest, without moving src dir itself for f in os.listdir(src): @@ -127,6 +133,15 @@ def moveDirContents(src, dest): dst_path = os.path.join(dest, f) shutil.move(src_path, dst_path) +def makeDirSymlink(link, target): + subprocess.check_call('mklink /J "%s" "%s"' % (link, target), shell=True) + +def makeFileSymlink(link, target): + # if ctypes.windll.shell32.IsUserAnAdmin(): + # subprocess.check_call('mklink "%s" "%s"' % (link, target), shell=True) + # else: + subprocess.check_call('mklink /H "%s" "%s"' % (link, target), shell=True) + def link_files_by_extension(source_dir, destination_dir): # Ensure the source directory exists if not os.path.exists(source_dir): @@ -146,9 +161,14 @@ def link_files_by_extension(source_dir, destination_dir): # Construct the destination path destination_path = os.path.join(destination_dir, filename) - # Create a symbolic link (change to shutil.copy if you want to copy instead) - os.symlink(file_path, destination_path) - print(f"Linked '{filename}' to '{destination_path}'") + # Check if the destination file already exists + if os.path.exists(destination_path): + # Delete the file from the destination location. + os.remove(destination_path) + + # Create a symbolic link from the source location to the destination location. + #print("making " + destination_path + "<-des source ->" + file_path) + makeFileSymlink(destination_path, file_path) def launch_local(MOD_ID, GAME): try: @@ -199,92 +219,18 @@ def openFolder(path): def reinstall(URL, MOD_ID, MODNAME, LINKTYPE, GAME): InstallDir = ModFolderPATH + MOD_ID AppdataPATH = os.getenv("APPDATA") - UniversalIsoPath = AppdataPATH + "\OpenGOAL-Mods\_iso_data" - ensure_jak_folders_exist() - #reinstall has a lot of duplicated logic not sure if there is a reason for this yet, but for now for jak 2 we can just delte the directory then call the install/launch function - if GAME == "jak2": - path_to_remove = InstallDir - if os.path.exists(path_to_remove): - shutil.rmtree(path_to_remove) - print(f"Path '{path_to_remove}' removed successfully.") - else: - print(f"Path '{path_to_remove}' does not exist.") - - launch(URL, MOD_ID, MODNAME, LINKTYPE, GAME) - return - - GKCOMMANDLINElist = [ - InstallDir + "\gk.exe", - "--proj-path", - InstallDir + "\\data", - "-boot", - "-fakeiso", - "-v", - ] + ensure_jak_folders_exist() - # if ISO_DATA has content, store this path to pass to the extractor - if exists(UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"): - iso_path = UniversalIsoPath + "\\" + GAME - + path_to_remove = InstallDir + if os.path.exists(path_to_remove): + shutil.rmtree(path_to_remove) + print(f"Path '{path_to_remove}' removed successfully.") else: - # if ISO_DATA is empty, prompt for their ISO and store its path. - root = tk.Tk() - print("Please select your iso.") - root.title("Select ISO") - root.geometry("230x1") - iso_path = filedialog.askopenfilename() - root.destroy() - if pathlib.Path(iso_path).is_file: - if not (pathlib.Path(iso_path).suffix).lower() == ".iso": - 1 / 0 - - # symlink isodata for custom levels art group (goalc doesnt take -f flag) - if exists(UniversalIsoPath + "//" + GAME +r"\Z6TAIL.DUP"): - makeDirSymlink(InstallDir + "\\data\\iso_data", UniversalIsoPath) - link_files_by_extension( UniversalIsoPath + "//" + GAME + "//VAG",InstallDir + "//data//out//" + GAME + "//iso") - - # Close Gk and goalc if they were open. - try_kill_process("gk.exe") - try_kill_process("goalc.exe") - print("Done update starting extractor\n") - if currentOS == "Windows": - extractor_command_list = [ - os.path.join(InstallDir, "extractor.exe"), - "-f", - iso_path, - ] - print("os is windows using " + extractor_command_list) - if currentOS == "Linux": - # We need to give the executibles execute permissions in Linux but this doesn't work - # chmod_command_list = ["cd" + os.path.join(LauncherDir), "chmod +x extractor goalc gk"] - # subprocess.Popen(chmod_command_list) - os.chmod(os.path.join(LauncherDir, "extractor"), stat.S_IXOTH) - print("Done chmods!") - # Then we need to call the Linux extractor when we do the next Popen - extractor_command_list = [ - os.path.join(LauncherDir), - "./extractor -f" + iso_path + "--proj-path" + InstallDir, - ] - print(extractor_command_list) - - extractor_result = subprocess.run(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir)) - - # wait for extractor to finish - while process_exists("extractor.exe"): - print("extractor.exe still running, sleeping for 1s") - time.sleep(1) - - # move the extrated contents to the universal launchers directory for next time. - if not (exists((UniversalIsoPath + r"" + "//" + GAME + "//" + "Z6TAIL.DUP"))): - os.makedirs(UniversalIsoPath, exist_ok=True) - print("The new directory is created!") - moveDirContents(InstallDir + "\\data\\iso_data", "" + UniversalIsoPath + "") - # replace iso_data with symlink - try_remove_dir(InstallDir + "\\data\\iso_data") - makeDirSymlink(InstallDir + "\\data\\iso_data", UniversalIsoPath) - - + print(f"Path '{path_to_remove}' does not exist.") + + launch(URL, MOD_ID, MODNAME, LINKTYPE, GAME) + return def replaceText(path, search_text, replace_text): # Check if the file exists @@ -626,6 +572,16 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): "/pc-settings.gc", r"/" + MOD_ID + "-settings.gc", ) + replaceText( + InstallDir + r"\data\decompiler\config\jak1_ntsc_black_label.jsonc", + "\"process_tpages\": true,", + "\"process_tpages\": false,", + ) + replaceText( + InstallDir + r"\data\decompiler\config\jak1_pal.jsonc", + "\"process_tpages\": true,", + "\"process_tpages\": false,", + ) # symlink isodata for custom levels art group (goalc doesnt take -f flag) if exists(UniversalIsoPath + r"" + "//" + GAME + "//" + "Z6TAIL.DUP"): @@ -640,13 +596,17 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): print("Done update starting extractor This one can take a few moments! \n") #Extract and compile + + if(GAME == "jak1"): - extractor_command_list = [InstallDir + "\extractor.exe", "-e", "-v", "-d", "-c"] + extractor_command_list = [InstallDir + "\extractor.exe", "-f", iso_path, "-e", "-v", "-d", "-c"] print(extractor_command_list) - subprocess.Popen(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir)) - while process_exists("extractor.exe"): - print("extractor.exe still running, sleeping for 1s") - time.sleep(1) + extractor_result = subprocess.run(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir)) + + if extractor_result.returncode ==0: + print("done extracting!") + else: + print("Extractor error!") if(GAME == "jak2"): getDecompiler(InstallDir) @@ -660,15 +620,17 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): '{"decompile_code": false}' ] #print(decompiler_command_list) - subprocess.Popen(decompiler_command_list, shell=True, cwd=os.path.abspath(InstallDir)) + decompiler_result = subprocess.Popen(decompiler_command_list, shell=True, cwd=os.path.abspath(InstallDir)) print("opened decompiler") #wait for decompiler before starting goalc #Decompiler - time.sleep(3) - while process_exists("decompiler.exe"): - print("decompiler.exe still running, sleeping for 1s") - time.sleep(1) + + + if decompiler_result.returncode ==0: + print("done with decompiler!") + else: + print("decompiler error!") goalc_command_list = [GoalCPATH, "--proj-path", @@ -683,27 +645,25 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): #open GoalC to build jak2, for jak 1 extractor can handle this. print("Opening the Compiler subprocess - Sleeping for 5 seconds so it has time to initalize.") - subprocess.Popen(goalc_command_list, shell=True, cwd=os.path.abspath(InstallDir)) - - - time.sleep(5) - while process_exists("extractor.exe"): - print("extractor.exe still running, sleeping for 1s") - time.sleep(1) - - #jak2hack this is only needed since extractor isnt aware of jak2 - while process_exists("goalc.exe"): - print("goalc.exe still running, sleeping for 1s") - time.sleep(1) + goalc_result = subprocess.Popen(goalc_command_list, shell=True, cwd=os.path.abspath(InstallDir)) + + #jak2hack this is only needed since extractor isnt aware of jak2 + if goalc_result.returncode ==0: + print("done goalc!") + else: + print("goalc error!") while not (exists(InstallDir + "/data/iso_data/" + GAME + "//Z6TAIL.DUP")) and (exists(InstallDir + "/data/iso_data/" + GAME + "//")): - time.sleep(5) - - if (exists(InstallDir + "/data/iso_data/" + GAME + "//Z6TAIL.DUP")) and not (exists(UniversalIsoPath + "//" + GAME + "//Z6TAIL.DUP")): - shutil.copytree( InstallDir + "/data/iso_data/" + GAME, UniversalIsoPath + "//" + GAME + "//") - - - + shutil.copytree( InstallDir + "/data/iso_data/" + GAME, UniversalIsoPath + "//" + GAME + "//") + + if exists(UniversalIsoPath + "//" + GAME +r"\Z6TAIL.DUP"): + #makeDirSymlink(InstallDir + "\\data\\iso_data", UniversalIsoPath) + link_files_by_extension( UniversalIsoPath + "//" + GAME + "//VAG",InstallDir + "//data//out//" + GAME + "//iso") + link_files_by_extension( UniversalIsoPath + "//" + GAME + "//SBK",InstallDir + "//data//out//" + GAME + "//iso") + link_files_by_extension( UniversalIsoPath + "//" + GAME + "//MUS",InstallDir + "//data//out//" + GAME + "//iso") + link_files_by_extension( UniversalIsoPath + "//" + GAME + "//STR",InstallDir + "//data//out//" + GAME + "//iso") + link_files_by_extension( UniversalIsoPath + "//" + GAME + "//DRIVERS",InstallDir + "//data//out//" + GAME + "//iso") + link_files_by_extension( UniversalIsoPath + "//" + GAME + "//TEXT",InstallDir + "//data//out//" + GAME + "//iso") # at this point we should be good to launch, these are just sanity checks that should never be reached From 27881c034256eae3fe9ba126a7706ddb56fefe90 Mon Sep 17 00:00:00 2001 From: Zedb0T <89345505+Zedb0T@users.noreply.github.com> Date: Sun, 17 Sep 2023 07:30:42 -0400 Subject: [PATCH 18/25] Add Jak 2 and Properly wait for a subprocess exist code --- openGOALModLauncher.py | 1 + utils/launcherUtils.py | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/openGOALModLauncher.py b/openGOALModLauncher.py index 36e8fec..a251239 100644 --- a/openGOALModLauncher.py +++ b/openGOALModLauncher.py @@ -263,6 +263,7 @@ def getRefreshedTableData(sort_col_idx): or FILTER_STR in mod["contributors"].lower() and mod["game"] != "jak2" or FILTER_STR in mod["tags"].lower() and mod["game"] != "jak2" or FILTER_STR == "i understand this is a test and will report any bugs to jak-project on github or in the opengoal discord" and mod["game"] == "jak2" + #or mod["access_date"] != "Not Installed" and mod["game"] == "jak2" show up after installing or require pw each time. ): if (INCLUDE_INSTALLED and mod["access_date"] != "Not Installed") or ( INCLUDE_UNINSTALLED and mod["access_date"] == "Not Installed" diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index 2155948..ddee508 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -203,7 +203,7 @@ def launch_local(MOD_ID, GAME): "-debug", ] print(GKCOMMANDLINElist) - subprocess.Popen(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir)) + subprocess.run(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir)) except Exception as e: # Catch all exceptions and print the error message. return str(e) @@ -580,6 +580,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): replaceText( InstallDir + r"\data\decompiler\config\jak1_pal.jsonc", "\"process_tpages\": true,", + "\"process_tpages\": false,", ) @@ -620,7 +621,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): '{"decompile_code": false}' ] #print(decompiler_command_list) - decompiler_result = subprocess.Popen(decompiler_command_list, shell=True, cwd=os.path.abspath(InstallDir)) + decompiler_result = subprocess.run(decompiler_command_list, shell=True, cwd=os.path.abspath(InstallDir)) print("opened decompiler") #wait for decompiler before starting goalc @@ -645,7 +646,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): #open GoalC to build jak2, for jak 1 extractor can handle this. print("Opening the Compiler subprocess - Sleeping for 5 seconds so it has time to initalize.") - goalc_result = subprocess.Popen(goalc_command_list, shell=True, cwd=os.path.abspath(InstallDir)) + goalc_result = subprocess.run(goalc_command_list, shell=True, cwd=os.path.abspath(InstallDir)) #jak2hack this is only needed since extractor isnt aware of jak2 if goalc_result.returncode ==0: @@ -687,7 +688,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): print("Is newest posted update older than what we have installed? " + str((LastWrite < LatestRel))) #ok launch game :D - subprocess.Popen(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir)) + subprocess.run(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir)) else: # if we dont need to update, then close any open instances of the game and just launch it From 512d84709abbd42f7a4bdf230e601b17ac7eec92 Mon Sep 17 00:00:00 2001 From: Zedb0T <89345505+Zedb0T@users.noreply.github.com> Date: Sun, 17 Sep 2023 08:27:06 -0400 Subject: [PATCH 19/25] Add threaded image retrieval fix symlinking --- buildlaunchercoreEXE.bat | 2 +- openGOALModLauncher.py | 102 ++++++++++++++++++++++----------------- openGOALModLauncher.spec | 10 ++-- utils/launcherUtils.py | 53 ++++++++++++-------- 4 files changed, 95 insertions(+), 72 deletions(-) diff --git a/buildlaunchercoreEXE.bat b/buildlaunchercoreEXE.bat index 509dea9..49207d9 100644 --- a/buildlaunchercoreEXE.bat +++ b/buildlaunchercoreEXE.bat @@ -1,6 +1,6 @@ set mypath=%~dp0 -pyinstaller --onefile openGOALModLauncher2.py --icon resources\appicon.ico --noconsole +pyinstaller --onefile openGOALModLauncher.py --icon resources\appicon.ico --noconsole move "%mypath%dist\openGOALModLauncher.exe" "%mypath%/" RENAME "%mypath%\openGOALModLauncher.exe" "openGOALModLauncher.exe" REM @RD /S /Q "%mypath%/build" diff --git a/openGOALModLauncher.py b/openGOALModLauncher.py index a251239..9182ae6 100644 --- a/openGOALModLauncher.py +++ b/openGOALModLauncher.py @@ -88,49 +88,40 @@ def exitWithError(): # grab images from web # url to splash screen image -url = "https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/modlaunchersplash.png" -jpg_data = ( - cloudscraper.create_scraper( - browser={"browser": "firefox", "platform": "windows", "mobile": False} - ) - .get(url) - .content -) -pil_image = Image.open(io.BytesIO(jpg_data)) -png_bio = io.BytesIO() -pil_image.save(png_bio, format="PNG") -splashfile = png_bio.getvalue() +def getPNGFromURL(URL): + result = None # Initialize the result variable + + def fetch_image(url): # Accept the URL parameter + nonlocal result # Access the result variable in the outer scope + jpg_data = ( + cloudscraper.create_scraper( + browser={"browser": "firefox", "platform": "windows", "mobile": False} + ) + .get(url) # Use the provided URL parameter + .content + ) + + pil_image = Image.open(io.BytesIO(jpg_data)) + png_bio = io.BytesIO() + pil_image.save(png_bio, format="PNG") + result = png_bio.getvalue() # Store the fetched image in the result variable + + thread = threading.Thread(target=fetch_image, args=(URL,)) # Pass the URL as an argument + thread.start() + thread.join() # Wait for the thread to finish + + return result # Return the fetched image data # url to icon for the window -url = "https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/appicon.ico" -jpg_data = ( - cloudscraper.create_scraper( - browser={"browser": "firefox", "platform": "windows", "mobile": False} - ) - .get(url) - .content -) - -pil_image = Image.open(io.BytesIO(jpg_data)) -png_bio = io.BytesIO() -pil_image.save(png_bio, format="PNG") -iconfile = png_bio.getvalue() - -# url to use if we have no image -url = "https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/noRepoImageERROR.png" -jpg_data = ( - cloudscraper.create_scraper( - browser={"browser": "firefox", "platform": "windows", "mobile": False} - ) - .get(url) - .content -) -pil_image = Image.open(io.BytesIO(jpg_data)) -png_bio = io.BytesIO() -pil_image.save(png_bio, format="PNG") -noimagefile = png_bio.getvalue() +splashfile = getPNGFromURL("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/modlaunchersplash.png") + +noimagefile = getPNGFromURL("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/noRepoImageERROR.png") + +iconfile = getPNGFromURL("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/appicon.ico") + +loadingimage = getPNGFromURL("https://cdn.discordapp.com/attachments/1012837220664750172/1151746308000989184/image.png") #make the modfolderpath if first install if not os.path.exists(ModFolderPATH): @@ -498,6 +489,14 @@ def handleModTableSelection(row): except: window["-SELECTEDMODIMAGE-"].update(githubUtils.resize_image(noimagefile, 500.0, 300.0)) +windowstatus = "main" + +launch_finished_event = threading.Event() +def launch_mod(tmpModURL): + [linkType, tmpModURL] = githubUtils.identifyLinkType(tmpModURL) + + launcherUtils.launch(tmpModURL, tmpModSelected, tmpModName, linkType, tmpGame) + launch_finished_event.set() def reset(): global LATEST_TABLE_DATA @@ -571,15 +570,28 @@ def reset(): # online launch window["-LAUNCH-"].update(disabled=True) window["-LAUNCH-"].update("Updating...") - [linkType, tmpModURL] = githubUtils.identifyLinkType(tmpModURL) - launcherUtils.launch(tmpModURL, tmpModSelected, tmpModName, linkType, tmpGame) + launch_thread = threading.Thread(target=launch_mod, args=(tmpModURL,)) + launch_thread.start() + #launch_thread.join() - # refresh table in case new mod installed + # Continue processing events while the background thread runs + while not launch_finished_event.is_set(): + event, values = window.read(timeout=100) + + if event == "Exit" or event == sg.WIN_CLOSED: + break + + # Handle other events here... + + # Reset windowstatus back to "main" + windowstatus = "main" + reset() + - # turn the button back on - window["-LAUNCH-"].update("Launch") - window["-LAUNCH-"].update(disabled=False) + # # turn the button back on + # window["-LAUNCH-"].update("Launch") + # window["-LAUNCH-"].update(disabled=False) elif event == "-VIEWFOLDER-": tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] subfolders = [f.name for f in os.scandir(ModFolderPATH) if f.is_dir()] diff --git a/openGOALModLauncher.spec b/openGOALModLauncher.spec index 53a7925..72568b4 100644 --- a/openGOALModLauncher.spec +++ b/openGOALModLauncher.spec @@ -1,8 +1,4 @@ # -*- mode: python ; coding: utf-8 -*- -from PyInstaller.utils.hooks import collect_data_files - -datas = [] -datas += collect_data_files('pycdlib') block_cipher = None @@ -12,8 +8,8 @@ a = Analysis( ['openGOALModLauncher.py'], pathex=[], binaries=[], - datas=datas, - hiddenimports=['pycdlib'], + datas=[], + hiddenimports=[], hookspath=[], hooksconfig={}, runtime_hooks=[], @@ -39,7 +35,7 @@ exe = EXE( upx=True, upx_exclude=[], runtime_tmpdir=None, - console=True, + console=False, disable_windowed_traceback=False, argv_emulation=False, target_arch=None, diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index ddee508..7abeab5 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -485,17 +485,18 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): print("We found ISO data from a previous mod installation! Lets use it!") print("Found in " + UniversalIsoPath +"//" + GAME + "//" + "Z6TAIL.DUP") iso_path = UniversalIsoPath + "\\" + GAME + + + while not (exists(InstallDir + "/data/iso_data/" + GAME + "//Z6TAIL.DUP")) and (exists(InstallDir + "/data/iso_data/" + GAME + "//")): + shutil.copytree( InstallDir + "/data/iso_data/" + GAME, UniversalIsoPath + "//" + GAME + "//") else: print("We did not find "+ GAME + "ISO data from a previous mod, lets ask for some!") #cleanup and remove a corrupted iso if os.path.exists(UniversalIsoPath + "//" + GAME) and os.path.isdir(UniversalIsoPath) and not (exists((UniversalIsoPath + "//" + GAME + "//" + "Z6TAIL.DUP"))): print("Removing corrupted iso destination...") shutil.rmtree(UniversalIsoPath + "//" + GAME) - print("corrupt iso removed.") + ensure_jak_folders_exist() #jak2hack - #since we are having users manually drop the iso into the folder creating it for them is nice :) - if GAME == "jak2": - os.makedirs(UniversalIsoPath + "//" + GAME) #if ISO_DATA is empty, prompt for their ISO and store its path. if GAME == "jak1": # if ISO_DATA is empty, prompt for their ISO and store its path. @@ -584,9 +585,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): "\"process_tpages\": false,", ) - # symlink isodata for custom levels art group (goalc doesnt take -f flag) - if exists(UniversalIsoPath + r"" + "//" + GAME + "//" + "Z6TAIL.DUP"): - makeDirSymlink(InstallDir + "/data/iso_data", UniversalIsoPath) + # if extractOnUpdate is True, check their ISO_DATA folder @@ -608,6 +607,8 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): print("done extracting!") else: print("Extractor error!") + + if(GAME == "jak2"): getDecompiler(InstallDir) @@ -642,20 +643,21 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): "(mi) (e)" ] - #print(goalc_command_list) + #print(goalc_command_list) - #open GoalC to build jak2, for jak 1 extractor can handle this. - print("Opening the Compiler subprocess - Sleeping for 5 seconds so it has time to initalize.") - goalc_result = subprocess.run(goalc_command_list, shell=True, cwd=os.path.abspath(InstallDir)) - - #jak2hack this is only needed since extractor isnt aware of jak2 - if goalc_result.returncode ==0: - print("done goalc!") - else: - print("goalc error!") + # symlink isodata for custom levels art group (goalc doesnt take -f flag) + if exists(UniversalIsoPath + r"" + "//" + GAME + "//" + "Z6TAIL.DUP"): + ensure_jak_folders_exist(); + makeDirSymlink(InstallDir + "/data/iso_data/" + GAME, UniversalIsoPath + "//" + GAME) + + # move the extrated contents to the universal launchers directory for next time. + if not (exists((UniversalIsoPath + r"\\" + GAME + "\Z6TAIL.DUP"))): + ensure_jak_folders_exist() + moveDirContents(InstallDir + "\\data\\iso_data/" + GAME, UniversalIsoPath + "//" + GAME) + # replace iso_data with symlink + try_remove_dir(InstallDir + "\\data\\iso_data/" + GAME) + makeDirSymlink(InstallDir + "\\data\\iso_data/" + GAME, UniversalIsoPath + "\\" + GAME) - while not (exists(InstallDir + "/data/iso_data/" + GAME + "//Z6TAIL.DUP")) and (exists(InstallDir + "/data/iso_data/" + GAME + "//")): - shutil.copytree( InstallDir + "/data/iso_data/" + GAME, UniversalIsoPath + "//" + GAME + "//") if exists(UniversalIsoPath + "//" + GAME +r"\Z6TAIL.DUP"): #makeDirSymlink(InstallDir + "\\data\\iso_data", UniversalIsoPath) @@ -666,6 +668,19 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): link_files_by_extension( UniversalIsoPath + "//" + GAME + "//DRIVERS",InstallDir + "//data//out//" + GAME + "//iso") link_files_by_extension( UniversalIsoPath + "//" + GAME + "//TEXT",InstallDir + "//data//out//" + GAME + "//iso") + if(GAME == "jak2"): + #open GoalC to build jak2, for jak 1 extractor can handle this. + print("Opening the Compiler subprocess - Sleeping for 5 seconds so it has time to initalize.") + goalc_result = subprocess.run(goalc_command_list, shell=True, cwd=os.path.abspath(InstallDir)) + + #jak2hack this is only needed since extractor isnt aware of jak2 + if goalc_result.returncode ==0: + print("done goalc!") + else: + print("goalc error!") + + + # at this point we should be good to launch, these are just sanity checks that should never be reached #update the timestamp of the local exe From 7999f568fd5a8feed4c181e6b0054366eb691c72 Mon Sep 17 00:00:00 2001 From: Zedb0T <89345505+Zedb0T@users.noreply.github.com> Date: Sun, 17 Sep 2023 09:10:51 -0400 Subject: [PATCH 20/25] Add launching image launch in a multi thread, clean up supprocesses --- openGOALModLauncher.py | 50 +++++++++++++++++++++++++++++++++++++----- utils/launcherUtils.py | 27 ++++++++++++++++++----- 2 files changed, 65 insertions(+), 12 deletions(-) diff --git a/openGOALModLauncher.py b/openGOALModLauncher.py index 9182ae6..2c5a628 100644 --- a/openGOALModLauncher.py +++ b/openGOALModLauncher.py @@ -316,6 +316,23 @@ def getRefreshedTableData(sort_col_idx): [sg.Image(key='-SPLASHIMAGE-', source=githubUtils.resize_image(splashfile, 970, 607), expand_y=True)] ]) ], + [sg.Frame( + title="", + key='-LOADINGFRAME-', + border_width=0, # Set border_width to 0 + visible=False, + element_justification="center", + vertical_alignment="center", + layout=[ + [sg.Image( + key='-LOADINGIMAGE-', + source=githubUtils.resize_image(loadingimage, 970, 607), + pad=(0, 0), # Set padding to 0 + expand_x=True, + expand_y=True, + )] + ] +)], [sg.Frame(title="", key='-MAINFRAME-', border_width=0, visible=False, layout= [ [ @@ -512,6 +529,22 @@ def reset(): reset() bootstart = time.time() while True: + + if windowstatus == "main" and window["-LOADINGFRAME-"].visible: + + # turn the button back on + window["-LAUNCH-"].update("Launch") + window["-LAUNCH-"].update(disabled=False) + + #We are done installing show the main menu again + window["-MAINFRAME-"].update(visible=True) + window["-MAINFRAME-"].unhide_row() + window["-LOADINGFRAME-"].update(visible=False) + window["-LOADINGFRAME-"].hide_row() + + # refresh table in case a new mod is installed + reset() + event, values = window.read(timeout=100) if event == "Exit" or event == sg.WIN_CLOSED: @@ -560,6 +593,15 @@ def reset(): elif event == "-REFRESH-": reset() elif event == "-LAUNCH-": + + windowstatus = "launching" + #hide all the buttons and display a window showing that it is installing + window["-LOADINGFRAME-"].update(visible=True) + window["-LOADINGFRAME-"].unhide_row() + window["-MAINFRAME-"].update(visible=False) + window["-MAINFRAME-"].hide_row() + window.refresh() + tmpModName = window["-SELECTEDMODNAME-"].get() tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] tmpModURL = window["-SELECTEDMODNAME-"].metadata["url"] @@ -574,7 +616,7 @@ def reset(): launch_thread.start() #launch_thread.join() - # Continue processing events while the background thread runs + # Continue processing events while the background thread runs while not launch_finished_event.is_set(): event, values = window.read(timeout=100) @@ -585,13 +627,9 @@ def reset(): # Reset windowstatus back to "main" windowstatus = "main" + launch_finished_event.clear() reset() - - - # # turn the button back on - # window["-LAUNCH-"].update("Launch") - # window["-LAUNCH-"].update(disabled=False) elif event == "-VIEWFOLDER-": tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] subfolders = [f.name for f in os.scandir(ModFolderPATH) if f.is_dir()] diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index 7abeab5..c2977f6 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -203,7 +203,10 @@ def launch_local(MOD_ID, GAME): "-debug", ] print(GKCOMMANDLINElist) - subprocess.run(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir)) + subprocess.run(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir), creationflags=subprocess.CREATE_NO_WINDOW,stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + stdin=subprocess.PIPE, + env=os.environ) except Exception as e: # Catch all exceptions and print the error message. return str(e) @@ -601,7 +604,10 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): if(GAME == "jak1"): extractor_command_list = [InstallDir + "\extractor.exe", "-f", iso_path, "-e", "-v", "-d", "-c"] print(extractor_command_list) - extractor_result = subprocess.run(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir)) + extractor_result = subprocess.run(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir), creationflags=subprocess.CREATE_NO_WINDOW,stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + stdin=subprocess.PIPE, + env=os.environ) if extractor_result.returncode ==0: print("done extracting!") @@ -622,7 +628,10 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): '{"decompile_code": false}' ] #print(decompiler_command_list) - decompiler_result = subprocess.run(decompiler_command_list, shell=True, cwd=os.path.abspath(InstallDir)) + decompiler_result = subprocess.run(decompiler_command_list, shell=True, cwd=os.path.abspath(InstallDir), creationflags=subprocess.CREATE_NO_WINDOW,stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + stdin=subprocess.PIPE, + env=os.environ) print("opened decompiler") #wait for decompiler before starting goalc @@ -649,7 +658,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): if exists(UniversalIsoPath + r"" + "//" + GAME + "//" + "Z6TAIL.DUP"): ensure_jak_folders_exist(); makeDirSymlink(InstallDir + "/data/iso_data/" + GAME, UniversalIsoPath + "//" + GAME) - + # move the extrated contents to the universal launchers directory for next time. if not (exists((UniversalIsoPath + r"\\" + GAME + "\Z6TAIL.DUP"))): ensure_jak_folders_exist() @@ -671,7 +680,10 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): if(GAME == "jak2"): #open GoalC to build jak2, for jak 1 extractor can handle this. print("Opening the Compiler subprocess - Sleeping for 5 seconds so it has time to initalize.") - goalc_result = subprocess.run(goalc_command_list, shell=True, cwd=os.path.abspath(InstallDir)) + goalc_result = subprocess.run(goalc_command_list, shell=True, cwd=os.path.abspath(InstallDir), creationflags=subprocess.CREATE_NO_WINDOW,stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + stdin=subprocess.PIPE, + env=os.environ) #jak2hack this is only needed since extractor isnt aware of jak2 if goalc_result.returncode ==0: @@ -703,7 +715,10 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): print("Is newest posted update older than what we have installed? " + str((LastWrite < LatestRel))) #ok launch game :D - subprocess.run(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir)) + subprocess.run(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir),creationflags=subprocess.CREATE_NO_WINDOW,stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + stdin=subprocess.PIPE, + env=os.environ) else: # if we dont need to update, then close any open instances of the game and just launch it From 5f13e33c18f193e511822beac2da1227ac740681 Mon Sep 17 00:00:00 2001 From: Zedb0T <89345505+Zedb0T@users.noreply.github.com> Date: Sun, 17 Sep 2023 09:13:35 -0400 Subject: [PATCH 21/25] fill more window --- openGOALModLauncher.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/openGOALModLauncher.py b/openGOALModLauncher.py index 2c5a628..40b6293 100644 --- a/openGOALModLauncher.py +++ b/openGOALModLauncher.py @@ -310,12 +310,23 @@ def getRefreshedTableData(sort_col_idx): # ----- Full layout ----- layout = [ - [sg.Frame(title="", key='-SPLASHFRAME-', border_width=0, size=(972, 609), visible=True, element_justification="center", vertical_alignment="center", - layout= - [ - [sg.Image(key='-SPLASHIMAGE-', source=githubUtils.resize_image(splashfile, 970, 607), expand_y=True)] - ]) - ], +[sg.Frame( + title="", + key='-SPLASHFRAME-', + border_width=0, # Set border_width to 0 + visible=True, + element_justification="center", + vertical_alignment="center", + layout=[ + [sg.Image( + key='-SPLASHIMAGE-', + source=githubUtils.resize_image(splashfile, 970, 607), + pad=(0, 0), # Set padding to 0 + expand_x=True, + expand_y=True + )] + ] +)], [sg.Frame( title="", key='-LOADINGFRAME-', @@ -435,7 +446,7 @@ def getRefreshedTableData(sort_col_idx): ] ] -window = sg.Window("OpenGOAL Mod Launcher", layout, icon=iconfile, finalize=True) +window = sg.Window("OpenGOAL Mod Launcher", layout, icon=iconfile, border_depth=0,finalize=True) def handleModTableSelection(row): global LATEST_TABLE_DATA mod = LATEST_TABLE_DATA[row] From 343719d8842232acd8dba3a02655164de900ec84 Mon Sep 17 00:00:00 2001 From: Zedb0T <89345505+Zedb0T@users.noreply.github.com> Date: Sun, 17 Sep 2023 10:15:11 -0400 Subject: [PATCH 22/25] Combine remote + local lists instead of comment out --- openGOALModLauncher.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/openGOALModLauncher.py b/openGOALModLauncher.py index 40b6293..ff63461 100644 --- a/openGOALModLauncher.py +++ b/openGOALModLauncher.py @@ -4,7 +4,6 @@ @author: Zed """ - # we will clean these up later but for now leave even unused imports import threading @@ -199,9 +198,20 @@ def fetch_image(url): # Accept the URL parameter LATEST_TABLE_SORT = [6, False] # wakeup sorted by last launch date def getRefreshedTableData(sort_col_idx): - # uncomment/comment the next two lines if you want to test with a local file - #mod_dict = requests.get("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/jak1_mods.json").json() - mod_dict = json.loads(open("resources/jak1_mods.json", "r").read()) + # Load data from the local file if it exists + local_file_path = "resources/jak1_mods.json" + if os.path.exists(local_file_path): + local_mods = json.loads(open(local_file_path, "r").read()) + # Load data from the remote URL + remote_url = "https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/jak1_mods.json" + remote_mods = requests.get(remote_url).json() + + # Initialize an empty dictionary to store the combined data + mod_dict = {} + + if os.path.exists(local_file_path): + # Merge the remote and local data while removing duplicates + mod_dict = {**remote_mods, **local_mods} mod_dict = dict(sorted(mod_dict.items(), key=lambda x: x[1]["release_date"], reverse=True)) From 96aed4df62908c58a2423802a8fd085247f6de54 Mon Sep 17 00:00:00 2001 From: Zedb0T <89345505+Zedb0T@users.noreply.github.com> Date: Sun, 17 Sep 2023 16:53:40 -0400 Subject: [PATCH 23/25] before removing process.runs --- openGOALModLauncher.py | 16 ++++++++++------ utils/launcherUtils.py | 43 ++++++++++++++++++++++-------------------- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/openGOALModLauncher.py b/openGOALModLauncher.py index ff63461..c124b5a 100644 --- a/openGOALModLauncher.py +++ b/openGOALModLauncher.py @@ -538,12 +538,16 @@ def launch_mod(tmpModURL): def reset(): global LATEST_TABLE_DATA - LATEST_TABLE_DATA = getRefreshedTableData(None) - window["-MODTABLE-"].update(values=LATEST_TABLE_DATA) - for i in range(len(sorted_table_headings)): - window["-MODTABLE-"].Widget.heading(i, text=sorted_table_headings[i]) - window["-MODTABLE-"].update(select_rows=[0]) - handleModTableSelection(0) + if window is not None: + LATEST_TABLE_DATA = getRefreshedTableData(None) + window["-MODTABLE-"].update(values=LATEST_TABLE_DATA) + for i in range(len(sorted_table_headings)): + window["-MODTABLE-"].Widget.heading(i, text=sorted_table_headings[i]) + window["-MODTABLE-"].update(select_rows=[0]) + handleModTableSelection(0) + else: + print("Window is closed. Cannot reset.") + # this is the main event loop where we handle user input diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index c2977f6..c19a6a0 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -25,7 +25,7 @@ import stat from pathlib import Path import time -import win32file + import ctypes EXTRACT_ON_UPDATE = "true" @@ -134,7 +134,8 @@ def moveDirContents(src, dest): shutil.move(src_path, dst_path) def makeDirSymlink(link, target): - subprocess.check_call('mklink /J "%s" "%s"' % (link, target), shell=True) + subprocess.check_call('mklink /J "%s" "%s"' % (link, target), shell=True) + def makeFileSymlink(link, target): # if ctypes.windll.shell32.IsUserAnAdmin(): @@ -203,7 +204,7 @@ def launch_local(MOD_ID, GAME): "-debug", ] print(GKCOMMANDLINElist) - subprocess.run(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir), creationflags=subprocess.CREATE_NO_WINDOW,stdout=subprocess.PIPE, + subprocess.run(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, env=os.environ) @@ -604,7 +605,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): if(GAME == "jak1"): extractor_command_list = [InstallDir + "\extractor.exe", "-f", iso_path, "-e", "-v", "-d", "-c"] print(extractor_command_list) - extractor_result = subprocess.run(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir), creationflags=subprocess.CREATE_NO_WINDOW,stdout=subprocess.PIPE, + extractor_result = subprocess.run(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, env=os.environ) @@ -628,7 +629,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): '{"decompile_code": false}' ] #print(decompiler_command_list) - decompiler_result = subprocess.run(decompiler_command_list, shell=True, cwd=os.path.abspath(InstallDir), creationflags=subprocess.CREATE_NO_WINDOW,stdout=subprocess.PIPE, + decompiler_result = subprocess.run(decompiler_command_list, shell=True, cwd=os.path.abspath(InstallDir), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, env=os.environ) @@ -655,38 +656,40 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): #print(goalc_command_list) # symlink isodata for custom levels art group (goalc doesnt take -f flag) - if exists(UniversalIsoPath + r"" + "//" + GAME + "//" + "Z6TAIL.DUP"): - ensure_jak_folders_exist(); - makeDirSymlink(InstallDir + "/data/iso_data/" + GAME, UniversalIsoPath + "//" + GAME) + # if exists(UniversalIsoPath + r"" + "//" + GAME + "//" + "Z6TAIL.DUP") and GAME == "jak1": + # ensure_jak_folders_exist(); + # makeDirSymlink(InstallDir + "/data/iso_data/" + GAME, UniversalIsoPath + "//" + GAME) # move the extrated contents to the universal launchers directory for next time. if not (exists((UniversalIsoPath + r"\\" + GAME + "\Z6TAIL.DUP"))): ensure_jak_folders_exist() moveDirContents(InstallDir + "\\data\\iso_data/" + GAME, UniversalIsoPath + "//" + GAME) # replace iso_data with symlink - try_remove_dir(InstallDir + "\\data\\iso_data/" + GAME) + try_remove_dir(InstallDir + "\\data\\iso_data/") makeDirSymlink(InstallDir + "\\data\\iso_data/" + GAME, UniversalIsoPath + "\\" + GAME) - if exists(UniversalIsoPath + "//" + GAME +r"\Z6TAIL.DUP"): - #makeDirSymlink(InstallDir + "\\data\\iso_data", UniversalIsoPath) - link_files_by_extension( UniversalIsoPath + "//" + GAME + "//VAG",InstallDir + "//data//out//" + GAME + "//iso") - link_files_by_extension( UniversalIsoPath + "//" + GAME + "//SBK",InstallDir + "//data//out//" + GAME + "//iso") - link_files_by_extension( UniversalIsoPath + "//" + GAME + "//MUS",InstallDir + "//data//out//" + GAME + "//iso") - link_files_by_extension( UniversalIsoPath + "//" + GAME + "//STR",InstallDir + "//data//out//" + GAME + "//iso") - link_files_by_extension( UniversalIsoPath + "//" + GAME + "//DRIVERS",InstallDir + "//data//out//" + GAME + "//iso") - link_files_by_extension( UniversalIsoPath + "//" + GAME + "//TEXT",InstallDir + "//data//out//" + GAME + "//iso") + if exists(UniversalIsoPath + "//" + GAME +r"\Z6TAIL.DUP") and not exists(InstallDir + "/data/iso_data/" + GAME + "//Z6TAIL.DUP"): + try_remove_dir(InstallDir + "\\data\\iso_data/") + makeDirSymlink(InstallDir + "\\data\\iso_data\\", UniversalIsoPath) + # link_files_by_extension( UniversalIsoPath + "//" + GAME + "//VAG",InstallDir + "//data//out//" + GAME + "//iso") + # link_files_by_extension( UniversalIsoPath + "//" + GAME + "//SBK",InstallDir + "//data//out//" + GAME + "//iso") + # link_files_by_extension( UniversalIsoPath + "//" + GAME + "//MUS",InstallDir + "//data//out//" + GAME + "//iso") + # link_files_by_extension( UniversalIsoPath + "//" + GAME + "//STR",InstallDir + "//data//out//" + GAME + "//iso") + # link_files_by_extension( UniversalIsoPath + "//" + GAME + "//DRIVERS",InstallDir + "//data//out//" + GAME + "//iso") + # link_files_by_extension( UniversalIsoPath + "//" + GAME + "//TEXT",InstallDir + "//data//out//" + GAME + "//iso") if(GAME == "jak2"): #open GoalC to build jak2, for jak 1 extractor can handle this. print("Opening the Compiler subprocess - Sleeping for 5 seconds so it has time to initalize.") - goalc_result = subprocess.run(goalc_command_list, shell=True, cwd=os.path.abspath(InstallDir), creationflags=subprocess.CREATE_NO_WINDOW,stdout=subprocess.PIPE, + time.sleep(17) + goalc_result = subprocess.run(goalc_command_list, shell=True, cwd=os.path.abspath(InstallDir), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, env=os.environ) #jak2hack this is only needed since extractor isnt aware of jak2 - if goalc_result.returncode ==0: + if goalc_result.returncode == 0: print("done goalc!") else: print("goalc error!") @@ -715,7 +718,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): print("Is newest posted update older than what we have installed? " + str((LastWrite < LatestRel))) #ok launch game :D - subprocess.run(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir),creationflags=subprocess.CREATE_NO_WINDOW,stdout=subprocess.PIPE, + subprocess.run(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir),stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, env=os.environ) From 8d034cc1344495007944fbb97a16c64f7cfc2461 Mon Sep 17 00:00:00 2001 From: Zedb0T <89345505+Zedb0T@users.noreply.github.com> Date: Sun, 17 Sep 2023 20:55:34 -0400 Subject: [PATCH 24/25] remove the stdout stuff need to see output to debug --- utils/launcherUtils.py | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index c19a6a0..ff40dc0 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -204,10 +204,7 @@ def launch_local(MOD_ID, GAME): "-debug", ] print(GKCOMMANDLINElist) - subprocess.run(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir), stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - stdin=subprocess.PIPE, - env=os.environ) + subprocess.run(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir) ) except Exception as e: # Catch all exceptions and print the error message. return str(e) @@ -605,10 +602,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): if(GAME == "jak1"): extractor_command_list = [InstallDir + "\extractor.exe", "-f", iso_path, "-e", "-v", "-d", "-c"] print(extractor_command_list) - extractor_result = subprocess.run(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir), stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - stdin=subprocess.PIPE, - env=os.environ) + extractor_result = subprocess.run(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir) ) if extractor_result.returncode ==0: print("done extracting!") @@ -629,10 +623,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): '{"decompile_code": false}' ] #print(decompiler_command_list) - decompiler_result = subprocess.run(decompiler_command_list, shell=True, cwd=os.path.abspath(InstallDir), stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - stdin=subprocess.PIPE, - env=os.environ) + decompiler_result = subprocess.run(decompiler_command_list, shell=True, cwd=os.path.abspath(InstallDir) ) print("opened decompiler") #wait for decompiler before starting goalc @@ -683,10 +674,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): #open GoalC to build jak2, for jak 1 extractor can handle this. print("Opening the Compiler subprocess - Sleeping for 5 seconds so it has time to initalize.") time.sleep(17) - goalc_result = subprocess.run(goalc_command_list, shell=True, cwd=os.path.abspath(InstallDir), stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - stdin=subprocess.PIPE, - env=os.environ) + goalc_result = subprocess.run(goalc_command_list, shell=True, cwd=os.path.abspath(InstallDir) ) #jak2hack this is only needed since extractor isnt aware of jak2 if goalc_result.returncode == 0: @@ -718,10 +706,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): print("Is newest posted update older than what we have installed? " + str((LastWrite < LatestRel))) #ok launch game :D - subprocess.run(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir),stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - stdin=subprocess.PIPE, - env=os.environ) + subprocess.run(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir),) else: # if we dont need to update, then close any open instances of the game and just launch it From 7366d6f1e5d29f0293fdc576d4a74f1435bb12ff Mon Sep 17 00:00:00 2001 From: dallmeyer <2515356+dallmeyer@users.noreply.github.com> Date: Sun, 17 Sep 2023 20:03:41 -0700 Subject: [PATCH 25/25] tweaks --- .gitignore | 2 +- Launcher with autoupdater.py | 2 +- openGOALModLauncher.py | 31 +- openGOALModLauncher.spec | 2 +- openGOALModLauncher2.py | 809 ----------------------------------- openGOALModLauncher2.spec | 45 -- requirements.txt | 3 +- resources/jak1_mods.json | 19 +- utils/launcherUtils.py | 15 +- utils/launcherUtilsbackup.py | 557 ------------------------ 10 files changed, 31 insertions(+), 1454 deletions(-) delete mode 100644 openGOALModLauncher2.py delete mode 100644 openGOALModLauncher2.spec delete mode 100644 utils/launcherUtilsbackup.py diff --git a/.gitignore b/.gitignore index 5242b9b..faea8cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ dist/* build/* .env -launcherUtilsbackup.py +utils/launcherUtilsbackup.py twitchcommands.spec resources/data/decompiler_out/* resources/data/iso_data/* diff --git a/Launcher with autoupdater.py b/Launcher with autoupdater.py index 8b5fad9..69a62cc 100644 --- a/Launcher with autoupdater.py +++ b/Launcher with autoupdater.py @@ -136,6 +136,6 @@ def download_newest_mod(): download_newest_mod() elif event == "launch_button": window.close() - subprocess.call([ AppdataPATH + "openGOALModLauncher2.exe"]) + subprocess.call([ AppdataPATH + "openGOALModLauncher.exe"]) window.close() diff --git a/openGOALModLauncher.py b/openGOALModLauncher.py index c124b5a..34f6c77 100644 --- a/openGOALModLauncher.py +++ b/openGOALModLauncher.py @@ -30,7 +30,7 @@ from datetime import datetime from pathlib import Path - +OPEN_SESAME = {"i understand this is a test and will report any bugs to jak-project on github or in the opengoal discord", "lbood"} sg.theme("DarkBlue3") @@ -46,7 +46,7 @@ def exitWithError(): LauncherDir = os.path.dirname(os.path.realpath(sys.executable)) # Detect if a user has downloaded a release directly, if so point them to the autoupdater - if LauncherDir != os.getenv("APPDATA") + "\\OpenGOAL-UnofficalModLauncher" and os.getlogin() != "NinjaPC": + if LauncherDir != os.getenv("APPDATA") + "\\OpenGOAL-UnofficalModLauncher" and os.getlogin() != "NinjaPC" and os.environ['COMPUTERNAME'] != 'DESKTOP-BBN1CMN': # Creating the tkinter window root = tkinter.Tk() root.winfo_toplevel().title("Error") @@ -198,10 +198,11 @@ def fetch_image(url): # Accept the URL parameter LATEST_TABLE_SORT = [6, False] # wakeup sorted by last launch date def getRefreshedTableData(sort_col_idx): - # Load data from the local file if it exists + # Load data from the local file if it exists local_file_path = "resources/jak1_mods.json" if os.path.exists(local_file_path): local_mods = json.loads(open(local_file_path, "r").read()) + # Load data from the remote URL remote_url = "https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/jak1_mods.json" remote_mods = requests.get(remote_url).json() @@ -212,6 +213,8 @@ def getRefreshedTableData(sort_col_idx): if os.path.exists(local_file_path): # Merge the remote and local data while removing duplicates mod_dict = {**remote_mods, **local_mods} + else: + mod_dict = {**remote_mods} mod_dict = dict(sorted(mod_dict.items(), key=lambda x: x[1]["release_date"], reverse=True)) @@ -257,15 +260,14 @@ def getRefreshedTableData(sort_col_idx): # mod["latest_available_update_date"] = f"{update_date:%Y-%m-%d %H:%M}" # only add to data if passes filter (if any) - if ( - FILTER_STR is None - or FILTER_STR == "" and mod["game"] != "jak2" - or FILTER_STR in mod_name.lower() and mod["game"] != "jak2" - or FILTER_STR in mod["contributors"].lower() and mod["game"] != "jak2" - or FILTER_STR in mod["tags"].lower() and mod["game"] != "jak2" - or FILTER_STR == "i understand this is a test and will report any bugs to jak-project on github or in the opengoal discord" and mod["game"] == "jak2" - #or mod["access_date"] != "Not Installed" and mod["game"] == "jak2" show up after installing or require pw each time. - ): + matches_filter = (FILTER_STR is None + or FILTER_STR == "" + or FILTER_STR in mod_name.lower() + or FILTER_STR in mod["contributors"].lower() + or FILTER_STR in mod["tags"].lower()) + + if ((mod["game"] != "jak2" and matches_filter) + or (mod["game"] == "jak2" and FILTER_STR in OPEN_SESAME)): if (INCLUDE_INSTALLED and mod["access_date"] != "Not Installed") or ( INCLUDE_UNINSTALLED and mod["access_date"] == "Not Installed" ): @@ -284,7 +286,7 @@ def getRefreshedTableData(sort_col_idx): (mod["videos_url"] if "videos_url" in mod else ""), (mod["photos_url"] if "photos_url" in mod else ""), (mod["image_override_url"] if "image_override_url" in mod else ""), - (mod["game"] if "game" in mod else "") + (mod["game"] if "game" in mod else "jak1") ] ) if sort_col_idx is None: @@ -631,7 +633,7 @@ def reset(): tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] tmpModURL = window["-SELECTEDMODNAME-"].metadata["url"] tmpGame = window["-SELECTEDMODNAME-"].metadata["game"] - if FILTER_STR == "i understand this is a test and will report any bugs to jak-project on github or in the opengoal discord": + if FILTER_STR in OPEN_SESAME: tmpGame = "jak2" # online launch @@ -675,7 +677,6 @@ def reset(): tmpGame = window["-SELECTEDMODNAME-"].metadata["game"] [linkType, tmpModURL] = githubUtils.identifyLinkType(tmpModURL) subfolders = [f.name for f in os.scandir(ModFolderPATH) if f.is_dir()] -#I understand this is a test and will report any bugs to jak-project on github or in the opengoal discord if tmpModSelected in subfolders: dir = dirs.user_data_dir + "\\OpenGOAL-Mods\\" + tmpModSelected ans = sg.popup_ok_cancel( diff --git a/openGOALModLauncher.spec b/openGOALModLauncher.spec index 72568b4..ae0c26d 100644 --- a/openGOALModLauncher.spec +++ b/openGOALModLauncher.spec @@ -41,5 +41,5 @@ exe = EXE( target_arch=None, codesign_identity=None, entitlements_file=None, - icon='resources\\appicon.ico', + icon=['resources\\appicon.ico'], ) diff --git a/openGOALModLauncher2.py b/openGOALModLauncher2.py deleted file mode 100644 index 144884f..0000000 --- a/openGOALModLauncher2.py +++ /dev/null @@ -1,809 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Thu Aug 25 18:33:45 2022 - -@author: Zed -""" - -# we will clean these up later but for now leave even unused imports -import threading - -from PIL import Image -from utils import launcherUtils, githubUtils -import PySimpleGUI as sg -import cloudscraper -import io -import json -import os.path -import requests -import time -from datetime import datetime -import sys -import webbrowser -import os -from os.path import exists -import shutil -import tkinter -from appdirs import AppDirs -from appdirs import AppDirs -import platform -import stat -from datetime import datetime -from pathlib import Path -import queue # Import the queue modul - - - -sg.theme("DarkBlue3") - -def openLauncherWebsite(): - webbrowser.open("https://opengoal-unofficial-mods.github.io/") - -def exitWithError(): - sys.exit(1) - -def getPNGFromURL(URL): - result = None # Initialize the result variable - - def fetch_image(url): # Accept the URL parameter - nonlocal result # Access the result variable in the outer scope - jpg_data = ( - cloudscraper.create_scraper( - browser={"browser": "firefox", "platform": "windows", "mobile": False} - ) - .get(url) # Use the provided URL parameter - .content - ) - - pil_image = Image.open(io.BytesIO(jpg_data)) - png_bio = io.BytesIO() - pil_image.save(png_bio, format="PNG") - result = png_bio.getvalue() # Store the fetched image in the result variable - - thread = threading.Thread(target=fetch_image, args=(URL,)) # Pass the URL as an argument - thread.start() - thread.join() # Wait for the thread to finish - - return result # Return the fetched image data - - - -# Folder where script is placed, It looks in this for the Exectuable -if getattr(sys, "frozen", False): - # If we are a pyinstaller exe get the path of this file, not python - LauncherDir = os.path.dirname(os.path.realpath(sys.executable)) - - # Detect if a user has downloaded a release directly, if so point them to the autoupdater - if LauncherDir != os.getenv("APPDATA") + "\\OpenGOAL-UnofficalModLauncher" and os.getlogin() != "NinjaPC": - # Creating the tkinter window - root = tkinter.Tk() - root.winfo_toplevel().title("Error") - root.title = "test" - root.geometry("700x150") - message = tkinter.Label( - root, - text="Launcher not installed properly! \n Please download from: \n https://opengoal-unofficial-mods.github.io/", - ) - message.config(font=("Courier", 14)) - message.pack() - - website_button = tkinter.Button(root, text="Visit Website", command=openLauncherWebsite) - website_button.pack() - - # Button for closing - - exit_button = tkinter.Button(root, text="Exit", command=exitWithError) - exit_button.pack() - - root.mainloop() -elif __file__: - # if we are running the .py directly use this path - LauncherDir = os.path.dirname(__file__) - -installpath = str(LauncherDir + "\\resources\\") - -# intialize default variables so they are never null - -dirs = AppDirs(roaming=True) - -# C:\Users\USERNAME\AppData\Roaming\OPENGOAL-UnofficalModLauncher\ -AppdataPATH = os.path.join(dirs.user_data_dir, "OPENGOAL-UnofficalModLauncher", "") - -# C:\Users\USERNAME\AppData\Roaming\OpenGOAL-Mods\ -ModFolderPATH = os.path.join(dirs.user_data_dir, "OpenGOAL-Mods", "") - -#spawn thread to get splash file - -splashfile = getPNGFromURL("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/modlaunchersplash.png") - -noimagefile = getPNGFromURL("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/noRepoImageERROR.png") - -iconfile = getPNGFromURL("https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/appicon.ico") - -loadingimage = getPNGFromURL("https://cdn.discordapp.com/attachments/1012837220664750172/1151746308000989184/image.png") - -#make the modfolderpath if first install -if not os.path.exists(ModFolderPATH): - os.makedirs(ModFolderPATH) - -table_headings = [ - "id", - "Name", - "Description", - "Tags", - "Contributors", - "Install Date", - "Last Launched", - # "Latest Update Date", - "URL", - "website_url", - "videos_url", - "photos_url", -] - -sorted_table_headings = [ - "id", - "Name", - "Description", - "Tags", - "Contributors", - "Install Date", - "Last Launched", - # "Latest Update Date", - "URL", - "website_url", - "videos_url", - "photos_url", -] - -col_vis = [ - False, - True, - False, - True, - True, - False, - True, - # True, - False, - False, - False, - False, -] - -vis_col_map = [ - 1, # name - 3, # tags - 4, # contributors - 6, # launch date -] - -col_width = [ - 0, # id - 40, # name - 0, # desc - 25, # tags - 25, # contributors - 0, # install date - 15, # launch date - 0, # url - 0, # website - 0, # videos - 0, # photos -] - -FILTER_STR = "" -INCLUDE_INSTALLED = True -INCLUDE_UNINSTALLED = True -LATEST_TABLE_SORT = [6, False] # wakeup sorted by last launch date - -def getRefreshedTableData(sort_col_idx): - - # Load data from the local file if it exists - local_file_path = "resources/jak1_mods.json" - if os.path.exists(local_file_path): - local_mods = json.loads(open(local_file_path, "r").read()) - # Load data from the remote URL - remote_url = "https://raw.githubusercontent.com/OpenGOAL-Unofficial-Mods/OpenGoal-ModLauncher-dev/main/resources/jak1_mods.json" - remote_mods = requests.get(remote_url).json() - - # Initialize an empty dictionary to store the combined data - mod_dict = {} - - if os.path.exists(local_file_path): - # Merge the remote and local data while removing duplicates - mod_dict = {**remote_mods, **local_mods} - - mod_dict = dict(sorted(mod_dict.items(), key=lambda x: x[1]["release_date"], reverse=True)) - - mod_table_data = [] - installed_mod_subfolders = { - f.name: f.stat().st_mtime for f in os.scandir(ModFolderPATH) if f.is_dir() - } - - for mod_id in mod_dict: - - mod = mod_dict[mod_id] - mod_name = mod["name"] - - mod["install_date"] = "Not Installed" - mod["access_date"] = "Not Installed" - - # determine local install/access datetime - if mod_id in installed_mod_subfolders: - mod["install_date"] = f"{datetime.fromtimestamp(installed_mod_subfolders[mod_id]):%Y-%m-%d %H:%M}" - - if exists(f"{ModFolderPATH}/{mod_id}/gk.exe"): - gk_stat = os.stat(f"{ModFolderPATH}/{mod_id}/gk.exe") - mod["access_date"] = f"{datetime.fromtimestamp(gk_stat.st_atime):%Y-%m-%d %H:%M}" - elif mod_name in installed_mod_subfolders: - # previous installation using mod_name (will migrate after this step) - mod["install_date"] = f"{datetime.fromtimestamp(installed_mod_subfolders[mod_name]):%Y-%m-%d %H:%M}" - # migrate folder to use mod_id instead of mod_name - shutil.move(ModFolderPATH + "/" + mod_name, ModFolderPATH + "/" + mod_id) - - if exists(f"{ModFolderPATH}/{mod_id}/gk.exe"): - gk_stat = os.stat(f"{ModFolderPATH}/{mod_id}/gk.exe") - mod["access_date"] = f"{datetime.fromtimestamp(gk_stat.st_atime):%Y-%m-%d %H:%M}" - - mod["contributors"] = ", ".join(mod["contributors"]) - mod["tags"].sort() - mod["tags"] = ", ".join(mod["tags"]) - - # determine latest available update datetime - disabled as too easy to get rate-limited by github (can we do in bulk maybe?) - # mod["latest_available_update_date"] = "1900-01-01 00:00" - # update_date = githubUtils.getLatestAvailableUpdateDatetime(mod["URL"]) - # if update_date: - # mod["latest_available_update_date"] = f"{update_date:%Y-%m-%d %H:%M}" - - # only add to data if passes filter (if any) - if ( - FILTER_STR is None - or FILTER_STR == "" and mod["game"] != "jak2" - or FILTER_STR in mod_name.lower() and mod["game"] != "jak2" - or FILTER_STR in mod["contributors"].lower() and mod["game"] != "jak2" - or FILTER_STR in mod["tags"].lower() and mod["game"] != "jak2" - or FILTER_STR == "i understand this is a test and will report any bugs to jak-project on github or in the opengoal discord" and mod["game"] == "jak2" - ): - if (INCLUDE_INSTALLED and mod["access_date"] != "Not Installed") or ( - INCLUDE_UNINSTALLED and mod["access_date"] == "Not Installed" - ): - mod_table_data.append( - [ - mod_id, - mod_name, - mod["desc"], - mod["tags"], - mod["contributors"], - mod["install_date"], - mod["access_date"], - # mod["latest_available_update_date"], - mod["URL"], - (mod["website_url"] if "website_url" in mod else ""), - (mod["videos_url"] if "videos_url" in mod else ""), - (mod["photos_url"] if "photos_url" in mod else ""), - (mod["image_override_url"] if "image_override_url" in mod else ""), - (mod["game"] if "game" in mod else "") - ] - ) - if sort_col_idx is None: - # not from a heading click, retain sorting - remapped_col_idx = LATEST_TABLE_SORT[0] - else: - # heading click, adjust sorting - remapped_col_idx = vis_col_map[sort_col_idx] - - if remapped_col_idx == LATEST_TABLE_SORT[0]: - LATEST_TABLE_SORT[1] = not LATEST_TABLE_SORT[1] # same column, flip asc/desc - else: - LATEST_TABLE_SORT[0] = remapped_col_idx - LATEST_TABLE_SORT[1] = True - - global sorted_table_headings, table_headings - sorted_table_headings = table_headings.copy() - sorted_table_headings[remapped_col_idx] += (" ↑" if LATEST_TABLE_SORT[1] else " ↓") - - if remapped_col_idx == 5 or remapped_col_idx == 6: # special sort for install/access date - mod_table_data.sort(key=lambda x: "0" if x[remapped_col_idx] == "Not Installed" else x[remapped_col_idx].lower()) - else: - mod_table_data.sort(key=lambda x: x[remapped_col_idx].lower()) - - if not LATEST_TABLE_SORT[1]: - mod_table_data.reverse() - - # print(mod_table_data) - return mod_table_data - -LATEST_TABLE_DATA = [] - -# ----- Full layout ----- -layout = [ -[sg.Frame( - title="", - key='-SPLASHFRAME-', - border_width=0, # Set border_width to 0 - visible=True, - element_justification="center", - vertical_alignment="center", - layout=[ - [sg.Image( - key='-SPLASHIMAGE-', - source=githubUtils.resize_image(splashfile, 970, 607), - pad=(0, 0), # Set padding to 0 - expand_x=True, - expand_y=True - )] - ] -)], -[sg.Frame( - title="", - key='-LOADINGFRAME-', - border_width=0, # Set border_width to 0 - visible=False, - element_justification="center", - vertical_alignment="center", - layout=[ - [sg.Image( - key='-LOADINGIMAGE-', - source=githubUtils.resize_image(loadingimage, 970, 607), - pad=(0, 0), # Set padding to 0 - expand_x=True, - expand_y=True, - )] - ] -)], - - [sg.Frame( - title="", - key='-MAINFRAME-', - border_width=0, - visible=False, - layout=[ - [ - sg.Column( - [ - [sg.Text( - "", - key="-SELECTEDMODNAME-", - font=("Helvetica", 13), - metadata={"id": "", "url": ""}, - )], - [sg.Text("", key="-SELECTEDMODDESC-", size=(55, 7))], - [sg.Text("Tags:", key="-SELECTEDMODTAGS-")], - [sg.Text("Contributors:", key="-SELECTEDMODCONTRIBUTORS-")], - [sg.Text("")], - [ - sg.Btn(button_text="Launch", key="-LAUNCH-", expand_x=True), - sg.Btn( - button_text="View ISO Folder", - key="-VIEWISOFOLDER-", - expand_x=True - ), - sg.Btn( - button_text="View Folder", - key="-VIEWFOLDER-", - expand_x=True - ), - sg.Btn( - button_text="Reinstall", - key="-REINSTALL-", - expand_x=True - ), - sg.Btn( - button_text="Uninstall", - key="-UNINSTALL-", - expand_x=True - ), - ], - [ - sg.Btn( - button_text="Website", - key="-WEBSITE-", - expand_x=True, - metadata={"url": ""}, - ), - sg.Btn( - button_text="Video(s)", - key="-VIDEOS-", - expand_x=True, - metadata={"url": ""}, - ), - sg.Btn( - button_text="Photo(s)", - key="-PHOTOS-", - expand_x=True, - metadata={"url": ""}, - ), - ], - ], - size=(400, 300), - expand_x=True, - expand_y=True, - ), - sg.Frame( - title="", - element_justification="center", - vertical_alignment="center", - border_width=0, - layout=[[sg.Image(key="-SELECTEDMODIMAGE-", expand_x=True, expand_y=True)]], - size=(500, 300), - ), - ], - [sg.HorizontalSeparator()], - [ - sg.Text("Search"), - sg.Input(expand_x=True, enable_events=True, key="-FILTER-"), - sg.Checkbox( - text="Show Installed", - default=True, - enable_events=True, - key="-SHOWINSTALLED-", - ), - sg.Checkbox( - text="Show Uninstalled", - default=True, - enable_events=True, - key="-SHOWUNINSTALLED-", - ), - ], - [ - sg.Table( - values=LATEST_TABLE_DATA, - headings=table_headings, - visible_column_map=col_vis, - col_widths=col_width, - auto_size_columns=False, - num_rows=15, - text_color="black", - background_color="lightblue", - alternating_row_color="white", - justification="left", - selected_row_colors="black on yellow", - key="-MODTABLE-", - expand_x=True, - expand_y=True, - enable_click_events=True, - ) - ], - ] - )] -] - - - - -window = sg.Window("OpenGOAL Mod Launcher", layout, icon=iconfile, border_depth=0,finalize=True) - -# this is the main event loop where we handle user input - -UPDATE_UI_EVENT = "-UPDATE-UI-" -ui_update_queue = queue.Queue() - -def handleModTableSelection(row): - global LATEST_TABLE_DATA - mod = LATEST_TABLE_DATA[row] - #print(mod) - - mod_id = mod[0] - mod_name = mod[1] - mod_desc = mod[2] - mod_tags = mod[3] - mod_contributors = mod[4] - mod_install_date = mod[5] - mod_access_date = mod[6] - mod_url = mod[7] - mod_website_url = mod[8] - mod_videos_url = mod[9] - mod_photos_url = mod[10] - mod_image_override_url = mod[11] - mod_game = mod[12] - - # load mod image - try: - mod_image_url = mod_image_override_url if mod_image_override_url != "" else githubUtils.returnModImageURL(mod_url) - r = requests.head(mod_image_url).status_code - if r == 200: - jpg_data = ( - cloudscraper.create_scraper( - browser={ - "browser": "firefox", - "platform": "windows", - "mobile": False, - } - ) - .get(mod_image_url) - .content - ) - - pil_image = Image.open(io.BytesIO(jpg_data)) - png_bio = io.BytesIO() - pil_image.save(png_bio, format="PNG") - png_data = png_bio.getvalue() - window["-SELECTEDMODIMAGE-"].update(githubUtils.resize_image(png_data, 500.0, 300.0)) - # prints the int of the status code. Find more at httpstatusrappers.com :) - else: - window["-SELECTEDMODIMAGE-"].update(githubUtils.resize_image(noimagefile, 500.0, 300.0)) - except: - window["-SELECTEDMODIMAGE-"].update(githubUtils.resize_image(noimagefile, 500.0, 300.0)) - # Create a dictionary with the data to update - update_data = { - "mod_name": mod_name, - "mod_desc": mod_desc, - "mod_tags": mod_tags, - "mod_contributors": mod_contributors, - "mod_access_date": mod_access_date, - "mod_website_url": mod_website_url, - "mod_videos_url": mod_videos_url, - "mod_photos_url": mod_photos_url, - "mod_image_override_url": mod_image_override_url, - "rowidx" : row, - # ... Include other data you want to update ... - } - - # Send an event to update the UI in the main thread - ui_update_queue.put(update_data) - window.write_event_value("-UPDATE-UI-", "Your update data here") - - -windowstatus = "main" - - -launch_finished_event = threading.Event() -def launch_mod(tmpModURL): - [linkType, tmpModURL] = githubUtils.identifyLinkType(tmpModURL) - - launcherUtils.launch(tmpModURL, tmpModSelected, tmpModName, linkType, tmpGame) - launch_finished_event.set() - - - - -def run_handle_mod_table_selection(row): - mod_selection_thread = threading.Thread(target=handleModTableSelection, args=(row,)) - mod_selection_thread.start() - -def reset(): - global LATEST_TABLE_DATA - LATEST_TABLE_DATA = getRefreshedTableData(None) - window["-MODTABLE-"].update(values=LATEST_TABLE_DATA) - for i in range(len(sorted_table_headings)): - window["-MODTABLE-"].Widget.heading(i, text=sorted_table_headings[i]) - window["-MODTABLE-"].update(select_rows=[0]) - handleModTableSelection(0) - -resetThread = threading.Thread(target=reset) -resetThread.start() - - -#reset() - -bootstart = time.time() - - - -while True: - - - if windowstatus == "main" and window["-LOADINGFRAME-"].visible: - - # turn the button back on - window["-LAUNCH-"].update("Launch") - window["-LAUNCH-"].update(disabled=False) - - #We are done installing show the main menu again - window["-MAINFRAME-"].update(visible=True) - window["-MAINFRAME-"].unhide_row() - window["-LOADINGFRAME-"].update(visible=False) - window["-LOADINGFRAME-"].hide_row() - - # refresh table in case a new mod is installed - reset() - event, values = window.read(timeout=100) - - - - if event == "Exit" or event == sg.WIN_CLOSED: - break - - try: - if event == UPDATE_UI_EVENT: - # Update the UI based on the data received from the secondary thread - - update_data = ui_update_queue.get_nowait() - mod = LATEST_TABLE_DATA[update_data["rowidx"]] - mod_id = mod[0] - mod_name = mod[1] - mod_desc = mod[2] - mod_tags = mod[3] - mod_contributors = mod[4] - mod_install_date = mod[5] - mod_access_date = mod[6] - mod_url = mod[7] - mod_website_url = mod[8] - mod_videos_url = mod[9] - mod_photos_url = mod[10] - mod_image_override_url = mod[11] - mod_game = mod[12] - update_data = values - mod_name = update_data["mod_name"] - mod_desc = update_data["mod_desc"] - mod_tags = update_data["mod_tags"] - mod_contributors = update_data["mod_contributors"] - mod_access_date = update_data["mod_access_date"] - mod_website_url = update_data["mod_website_url"] - mod_videos_url = update_data["mod_videos_url"] - mod_photos_url = update_data["mod_photos_url"] - mod_image_override_url = update_data["mod_image_override_url"] - - # Update the UI elements here... - window["-LAUNCH-"].update( - "Install" if mod_access_date == "Not Installed" else "Launch" - ) - window["-SELECTEDMODNAME-"].update(mod_name) - window["-SELECTEDMODNAME-"].metadata["id"] = mod_id - window["-SELECTEDMODNAME-"].metadata["url"] = mod_url - window["-SELECTEDMODNAME-"].metadata["image_override_url"] = mod_image_override_url - - - window["-SELECTEDMODNAME-"].metadata["game"] = mod_game - - - window["-WEBSITE-"].metadata["url"] = mod_website_url - - window["-VIDEOS-"].metadata["url"] = mod_videos_url - - window["-PHOTOS-"].metadata["url"] = mod_photos_url - # ... Update other UI elements ... - except queue.Empty: - pass # No data in the queue, continue processing other events - # Handle other events and user interactions as needed - # ... - - if event == "__TIMEOUT__": - if bootstart is not None: - curtime = time.time() - if curtime - bootstart > 3: - # switch from splash screen to main screen after 3s - bootstart = None - window["-MAINFRAME-"].update(visible=True) - window["-MAINFRAME-"].unhide_row() - window["-SPLASHFRAME-"].update(visible=False) - window["-SPLASHFRAME-"].hide_row() - window.refresh() - # print("SIZE:", window.size) - elif isinstance(event, tuple): - if event[0] == "-MODTABLE-": - row = event[2][0] - col = event[2][1] - if row == None: - # empty row, do nothing - continue - elif row == -1: - # heading row, sort by col - LATEST_TABLE_DATA = getRefreshedTableData(col) - window["-MODTABLE-"].update(values=LATEST_TABLE_DATA) - for i in range(len(sorted_table_headings)): - window["-MODTABLE-"].Widget.heading(i, text=sorted_table_headings[i]) - else: - # data row, mod selected - run_handle_mod_table_selection(row) - elif event == "-FILTER-": - FILTER_STR = values["-FILTER-"].lower() - LATEST_TABLE_DATA = getRefreshedTableData(None) - window["-MODTABLE-"].update(values=LATEST_TABLE_DATA) - elif event == "-SHOWINSTALLED-": - INCLUDE_INSTALLED = window["-SHOWINSTALLED-"].get() - LATEST_TABLE_DATA = getRefreshedTableData(None) - window["-MODTABLE-"].update(values=LATEST_TABLE_DATA) - elif event == "-SHOWUNINSTALLED-": - INCLUDE_UNINSTALLED = window["-SHOWUNINSTALLED-"].get() - LATEST_TABLE_DATA = getRefreshedTableData(None) - window["-MODTABLE-"].update(values=LATEST_TABLE_DATA) - elif event == "-REFRESH-": - reset() - - elif event == "-LAUNCH-": - windowstatus = "launching" - #hide all the buttons and display a window showing that it is installing - window["-LOADINGFRAME-"].update(visible=True) - window["-LOADINGFRAME-"].unhide_row() - window["-MAINFRAME-"].update(visible=False) - window["-MAINFRAME-"].hide_row() - window.refresh() - - tmpModName = window["-SELECTEDMODNAME-"].get() - tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] - tmpModURL = window["-SELECTEDMODNAME-"].metadata["url"] - tmpGame = window["-SELECTEDMODNAME-"].metadata["game"] - if FILTER_STR == "i understand this is a test and will report any bugs to jak-project on github or in the opengoal discord": - tmpGame = "jak2" - - # online launch - window["-LAUNCH-"].update(disabled=True) - window["-LAUNCH-"].update("Updating...") - launch_thread = threading.Thread(target=launch_mod, args=(tmpModURL,)) - launch_thread.start() - #launch_thread.join() - - # Continue processing events while the background thread runs - while not launch_finished_event.is_set(): - event, values = window.read(timeout=100) - - if event == "Exit" or event == sg.WIN_CLOSED: - break - - # Handle other events here... - - # Reset windowstatus back to "main" - windowstatus = "main" - - reset() - elif event == "-VIEWFOLDER-": - tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] - subfolders = [f.name for f in os.scandir(ModFolderPATH) if f.is_dir()] - - if tmpModSelected in subfolders: - dir = dirs.user_data_dir + "\\OpenGOAL-Mods\\" + tmpModSelected - launcherUtils.openFolder(dir) - else: - sg.Popup("Selected mod is not installed", keep_on_top=True, icon=iconfile) - elif event == "-VIEWISOFOLDER-": - dir = dirs.user_data_dir + "\OpenGOAL-Mods\_iso_data" - launcherUtils.ensure_jak_folders_exist() - launcherUtils.openFolder(dir) - elif event == "-REINSTALL-": - tmpModName = window["-SELECTEDMODNAME-"].get() - tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] - tmpModURL = window["-SELECTEDMODNAME-"].metadata["url"] - tmpGame = window["-SELECTEDMODNAME-"].metadata["game"] - [linkType, tmpModURL] = githubUtils.identifyLinkType(tmpModURL) - subfolders = [f.name for f in os.scandir(ModFolderPATH) if f.is_dir()] -#I understand this is a test and will report any bugs to jak-project on github or in the opengoal discord - if tmpModSelected in subfolders: - dir = dirs.user_data_dir + "\\OpenGOAL-Mods\\" + tmpModSelected - ans = sg.popup_ok_cancel( - "Confirm: reinstalling " - + dir - + " \n\nNote: this will re-extract texture_replacements too", - icon=iconfile, - ) - if ans == "OK": - launcherUtils.reinstall(tmpModURL, tmpModSelected, tmpModName, linkType, tmpGame) - reset() - else: - sg.Popup("Selected mod is not installed", keep_on_top=True, icon=iconfile) - elif event == "-UNINSTALL-": - tmpModSelected = window["-SELECTEDMODNAME-"].metadata["id"] - subfolders = [f.name for f in os.scandir(ModFolderPATH) if f.is_dir()] - - if tmpModSelected in subfolders: - dir = dirs.user_data_dir + "\\OpenGOAL-Mods\\" + tmpModSelected - ans = sg.popup_ok_cancel("Confirm: uninstalling " + dir, icon=iconfile) - if ans == "OK": - launcherUtils.try_remove_dir(dir) - reset() - sg.popup("Uninstalled " + tmpModSelected, icon=iconfile) - else: - sg.Popup("Selected mod is not installed", keep_on_top=True, icon=iconfile) - elif event == "-WEBSITE-": - window = window.refresh() - url = window["-WEBSITE-"].metadata["url"] - if url: - webbrowser.open(url) - elif event == "-VIDEOS-": - window = window.refresh() - url = window["-VIDEOS-"].metadata["url"] - if url: - webbrowser.open(url) - elif event == "-PHOTOS-": - window = window.refresh() - url = window["-PHOTOS-"].metadata["url"] - if url: - webbrowser.open(url) - else: - print("unhandled event:", event, values) - -window.close() - -#join threads -resetThread.join() \ No newline at end of file diff --git a/openGOALModLauncher2.spec b/openGOALModLauncher2.spec deleted file mode 100644 index 9ec8d67..0000000 --- a/openGOALModLauncher2.spec +++ /dev/null @@ -1,45 +0,0 @@ -# -*- mode: python ; coding: utf-8 -*- - - -block_cipher = None - - -a = Analysis( - ['openGOALModLauncher2.py'], - pathex=[], - binaries=[], - datas=[], - hiddenimports=[], - hookspath=[], - hooksconfig={}, - runtime_hooks=[], - excludes=[], - win_no_prefer_redirects=False, - win_private_assemblies=False, - cipher=block_cipher, - noarchive=False, -) -pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) - -exe = EXE( - pyz, - a.scripts, - a.binaries, - a.zipfiles, - a.datas, - [], - name='openGOALModLauncher2', - debug=False, - bootloader_ignore_signals=False, - strip=False, - upx=True, - upx_exclude=[], - runtime_tmpdir=None, - console=False, - disable_windowed_traceback=False, - argv_emulation=False, - target_arch=None, - codesign_identity=None, - entitlements_file=None, - icon='resources\\appicon.ico', -) diff --git a/requirements.txt b/requirements.txt index f970537..52e2ae9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,5 +6,4 @@ requests Pillow progressbar cloudscraper -appdirs - +appdirs \ No newline at end of file diff --git a/resources/jak1_mods.json b/resources/jak1_mods.json index f6d9988..9217025 100644 --- a/resources/jak1_mods.json +++ b/resources/jak1_mods.json @@ -455,7 +455,7 @@ "orange_demon": { "name": "Orange Demon Challenge", "desc": "Play through the entire game while being chased by Daxter!", - "contributors": ["Hat Kid"], + "contributors": ["Hat-Kid"], "tags": [ "gameplay-mod", "custom-enemy", @@ -529,8 +529,6 @@ "website_url": "https://github.com/dallmeyer/jak-up/blob/main/README.md", "game": "jak1" }, - - "candy_pop_keira": { "name": "Candy Pop Keira", "desc": "Keira's original outfit, but with a candy pop color scheme.", @@ -545,20 +543,17 @@ "game": "jak1" }, "mod_base_2": { - "name": "Jak 2", - "desc": "Early test build. WARNING: the levels take up ~400MB, and will take a couple minutes to install.", - "contributors": ["barg034"], + "name": "Jak II", + "desc": "NOTE: this is a test, please report any bugs to jak-project on github or in the OpenGOAL discord", + "contributors": ["water111, XTVaser, ManDude, Hat-Kid, Ziemas"], "tags": [ "beta", - "gameplay-mod", - "challenge", - "custom-level", "speedrunning" ], - "release_date": "2023-08-10", + "release_date": "2023-09-18", "URL": "https://github.com/OpenGOAL-Mods/OG-Mod-Base/releases", - "image_override_url": "https://cdn.discordapp.com/attachments/1007077732032721037/1139110276273287239/image.png", - "website_url": "https://github.com/dallmeyer/jak-up/blob/main/README.md", + "image_override_url": "https://opengoal.dev/gallery/jak2/dev/demo-1.png", + "website_url": "https://github.com/open-goal/jak-project/issues", "game": "jak2" } } diff --git a/utils/launcherUtils.py b/utils/launcherUtils.py index ff40dc0..aa100e9 100644 --- a/utils/launcherUtils.py +++ b/utils/launcherUtils.py @@ -25,7 +25,6 @@ import stat from pathlib import Path import time - import ctypes EXTRACT_ON_UPDATE = "true" @@ -200,8 +199,7 @@ def launch_local(MOD_ID, GAME): "jak2", "--", "-boot", - "-fakeiso", - "-debug", + "-fakeiso" ] print(GKCOMMANDLINElist) subprocess.run(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir) ) @@ -216,7 +214,6 @@ def openFolder(path): print(path) subprocess.run([FILEBROWSER_PATH, path]) -#tmpModURL, tmpModSelected, tmpModName, linkType, tmpGame def reinstall(URL, MOD_ID, MODNAME, LINKTYPE, GAME): InstallDir = ModFolderPATH + MOD_ID AppdataPATH = os.getenv("APPDATA") @@ -295,8 +292,6 @@ def ensure_jak_folders_exist(): #check if we have decompiler in the path, if not check if we have a backup, if so use it, if not download a backup then use it def getDecompiler(path): - # print("AHHHHHHHH") - # time.sleep(15) decompiler_exe = "decompiler.exe" decompiler_url = "https://github.com/OpenGOAL-Mods/OG-Mod-Base/raw/main/out/build/Release/bin/decompiler.exe" @@ -359,7 +354,6 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): "--", "-boot", "-fakeiso", - "-debug", ] # store Latest Release and check our local date too. @@ -505,7 +499,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): print("Please select your iso.") root.title("Select ISO") root.geometry("230x1") - iso_path = filedialog.askopenfilename() + iso_path = filedialog.askopenfilename(title="Please select your ISO") root.destroy() if pathlib.Path(iso_path).is_file: if not (pathlib.Path(iso_path).suffix).lower() == ".iso": @@ -672,8 +666,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): if(GAME == "jak2"): #open GoalC to build jak2, for jak 1 extractor can handle this. - print("Opening the Compiler subprocess - Sleeping for 5 seconds so it has time to initalize.") - time.sleep(17) + print("Opening the Compiler subprocess.") goalc_result = subprocess.run(goalc_command_list, shell=True, cwd=os.path.abspath(InstallDir) ) #jak2hack this is only needed since extractor isnt aware of jak2 @@ -706,7 +699,7 @@ def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): print("Is newest posted update older than what we have installed? " + str((LastWrite < LatestRel))) #ok launch game :D - subprocess.run(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir),) + subprocess.run(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir)) else: # if we dont need to update, then close any open instances of the game and just launch it diff --git a/utils/launcherUtilsbackup.py b/utils/launcherUtilsbackup.py deleted file mode 100644 index e0f91b3..0000000 --- a/utils/launcherUtilsbackup.py +++ /dev/null @@ -1,557 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri Aug 12 06:51:37 2022 - -@author: Zed -""" -from datetime import datetime -from os.path import exists -from tkinter import filedialog -from utils import githubUtils -import json -import os -import pathlib -import progressbar -import requests -import shutil -import subprocess -import sys -import time -import tkinter as tk -import urllib.request -import zipfile -from appdirs import AppDirs -import platform -import stat - - -EXTRACT_ON_UPDATE = "true" -FILE_DATE_TO_CHECK = "gk.exe" -UPDATE_FILE_EXTENTION = ".zip" - -# Folder where script is placed, It looks in this for the Exectuable -if getattr(sys, "frozen", False): - LauncherDir = os.path.dirname(os.path.realpath(sys.executable)) -elif __file__: - LauncherDir = os.path.dirname(__file__) - -extractOnUpdate = bool(str(EXTRACT_ON_UPDATE).replace("t", "T").replace("f", "F")) -ExecutableName = str( - FILE_DATE_TO_CHECK -) # Executable we're checking the 'modified' time of -FileExt = str( - UPDATE_FILE_EXTENTION -) # content_type of the .deb release is also "application\zip", so rely on file ext -FileIdent = "" # If we ever get to multiple .zip files in a release, include other identifying information from the name -dirs = AppDirs(roaming=True) -currentOS = platform.system() -ModFolderPATH = os.path.join(dirs.user_data_dir, "OpenGOAL-Mods", "") -AppdataPATH = dirs.user_data_dir - - -pbar = None - - -def installedlist(PATH): - print(PATH) - scanDir = PATH - directories = [ - d - for d in os.listdir(scanDir) - if os.path.isdir(os.path.join(os.path.abspath(scanDir), d)) - ] - print(directories) - for i in directories: - print(i) - print(os.path.dirname(os.path.dirname(PATH))) - - -def show_progress(block_num, block_size, total_size): - if total_size > 0: - global pbar - if pbar is None: - pbar = progressbar.ProgressBar(maxval=total_size) - pbar.start() - - downloaded = block_num * block_size - - if downloaded < total_size: - pbar.update(downloaded) - else: - pbar.finish() - pbar = None - - -def process_exists(process_name): - call = "TASKLIST", "/FI", "imagename eq %s" % process_name - try: - # use buildin check_output right away - output = subprocess.check_output(call).decode() - # check in last line for process name - last_line = output.strip().split("\r\n")[-1] - # because Fail message could be translated - return last_line.lower().startswith(process_name.lower()) - except: - return False - - -def try_kill_process(process_name): - if process_exists(process_name): - os.system("taskkill /f /im " + process_name) - - -def try_remove_file(file): - if exists(file): - os.remove(file) - - -def try_remove_dir(dir): - if exists(dir): - shutil.rmtree(dir) - - -def local_mod_image(MOD_ID): - path = ModFolderPATH + MOD_ID + "\\ModImage.png" - if exists(path): - return path - return None - - -def launch_local(MOD_ID, GAME): - try: - # Close Gk and goalc if they were open. - try_kill_process("gk.exe") - try_kill_process("goalc.exe") - - time.sleep(1) - InstallDir = ModFolderPATH + MOD_ID - - UniversalIsoPath = AppdataPATH + "\OpenGOAL\jak1\mods\data\iso_data" - - GKCOMMANDLINElist = [ - os.path.abspath(InstallDir + "\gk.exe"), # Using os.path.abspath to get the absolute path. - "--proj-path", - os.path.abspath(InstallDir + "\\data"), # Using absolute path for data folder too. - "-boot", - "-fakeiso", - "-v", - ] - if(GAME == "jak2"): - GKCOMMANDLINElist = [ - InstallDir + "\gk.exe", - "--proj-path", - InstallDir + "\\data", - "-boot", - "-fakeiso", - "-v", - "--game", - "jak2", - "debug", - ] - print(GKCOMMANDLINElist) - subprocess.Popen(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir)) - except Exception as e: # Catch all exceptions and print the error message. - return str(e) - - -def openFolder(path): - FILEBROWSER_PATH = os.path.join(os.getenv("WINDIR"), "explorer.exe") - subprocess.run([FILEBROWSER_PATH, path]) - - -def reinstall(MOD_ID): - InstallDir = ModFolderPATH + MOD_ID - AppdataPATH = os.getenv("APPDATA") - UniversalIsoPath = AppdataPATH + "\OpenGOAL\jak1\mods\data\iso_data" - - GKCOMMANDLINElist = [ - InstallDir + "\gk.exe", - "--proj-path", - InstallDir + "\\data", - "-boot", - "-fakeiso", - "-v", - ] - - # if ISO_DATA has content, store this path to pass to the extractor - if exists(UniversalIsoPath + r"\jak1\Z6TAIL.DUP"): - iso_path = UniversalIsoPath + "\jak1" - - else: - # if ISO_DATA is empty, prompt for their ISO and store its path. - root = tk.Tk() - print("Please select your iso.") - root.title("Select ISO") - root.geometry("230x1") - iso_path = filedialog.askopenfilename() - root.destroy() - if pathlib.Path(iso_path).is_file: - if not (pathlib.Path(iso_path).suffix).lower() == ".iso": - 1 / 0 - - # Close Gk and goalc if they were open. - try_kill_process("gk.exe") - try_kill_process("goalc.exe") - print("Done update starting extractor\n") - if currentOS == "Windows": - extractor_command_list = [ - os.path.join(InstallDir, "extractor.exe"), - "-f", - iso_path, - ] - if currentOS == "Linux": - # We need to give the executibles execute permissions in Linux but this doesn't work - # chmod_command_list = ["cd" + os.path.join(LauncherDir), "chmod +x extractor goalc gk"] - # subprocess.Popen(chmod_command_list) - os.chmod(os.path.join(LauncherDir, "extractor"), stat.S_IXOTH) - print("Done chmods!") - # Then we need to call the Linux extractor when we do the next Popen - extractor_command_list = [ - os.path.join(LauncherDir), - "./extractor -f" + iso_path + "--proj-path" + InstallDir, - ] - print(extractor_command_list) - - subprocess.Popen(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir)) - - # wait for extractor to finish - while process_exists("extractor.exe"): - print("extractor.exe still running, sleeping for 1s") - time.sleep(1) - - # move the extrated contents to the universal launchers directory for next time. - if not (exists((UniversalIsoPath + r"\jak1\Z6TAIL.DUP"))): - - # os.makedirs(AppdataPATH + "\OpenGOAL-Launcher\data\iso_data") - print("The new directory is created!") - shutil.move(InstallDir + "/data/iso_data", "" + UniversalIsoPath + "") - - # try_remove_dir(InstallDir + "/data/iso_data") - # os.symlink("" + UniversalIsoPath +"", InstallDir + "/data/iso_data") - - -def replaceText(path, search_text, replace_text): - # Check if the file exists - if not os.path.isfile(path): - print(f"File '{path}' does not exist.") - return - - # Open the file in read-only mode - with open(path, "r") as file: - data = file.read() - - # Perform the search and replace operation - data = data.replace(search_text, replace_text) - - # Open the file in write mode to write the replaced content - with open(path, "w") as file: - file.write(data) - - print(f"Text replaced successfully in file '{path}'.") - - -def launch(URL, MOD_ID, MOD_NAME, LINK_TYPE,GAME): - print(GAME) - print(GAME) - print(GAME) - print(GAME) - print(GAME) - print(GAME) - print(GAME) - print(GAME) - print(GAME) - print(GAME) - print(GAME) - print(GAME) - if URL is None: - return - - # start of update check method - # Github API Call - launchUrl = URL - if LINK_TYPE == githubUtils.LinkTypes.BRANCH: - launchUrl = githubUtils.branchToApiURL(URL) - LatestRelAssetsURL = "" - - print("\nlaunching from " + launchUrl) - PARAMS = {"address": "yolo"} - r = json.loads(json.dumps(requests.get(url=launchUrl, params=PARAMS).json())) - - # paths - InstallDir = ModFolderPATH + MOD_ID - AppdataPATH = os.getenv("APPDATA") - UniversalIsoPath = AppdataPATH + "\OpenGOAL\jak1\mods\data\iso_data" - - GKCOMMANDLINElist = [ - InstallDir + "\gk.exe", - "--proj-path", - InstallDir + "\\data", - "-boot", - "-fakeiso", - "-v", - ] - - if (GAME == "jak2"): - GKCOMMANDLINElist = [ - InstallDir + "\gk.exe", - "--proj-path", - InstallDir + "\\data", - "-boot", - "-fakeiso", - "-v", - "--game", - "jak2", - "debug", - ] - - # store Latest Release and check our local date too. - if LINK_TYPE == githubUtils.LinkTypes.BRANCH: - LatestRel = datetime.strptime( - r.get("commit") - .get("commit") - .get("author") - .get("date") - .replace("T", " ") - .replace("Z", ""), - "%Y-%m-%d %H:%M:%S", - ) - LatestRelAssetsURL = githubUtils.branchToArchiveURL(URL) - elif LINK_TYPE == githubUtils.LinkTypes.RELEASE: - LatestRel = datetime.strptime( - r[0].get("published_at").replace("T", " ").replace("Z", ""), - "%Y-%m-%d %H:%M:%S", - ) - assets = json.loads(json.dumps(requests.get(url=r[0].get("assets_url"), params=PARAMS).json())) - for asset in assets: - if "linux" not in asset.get("name") and "macos" not in asset.get("name") and "json" not in asset.get("name"): - LatestRelAssetsURL = asset.get("browser_download_url") - break - - # response = requests.get(url=LatestRelAssetsURL, params=PARAMS) - # content_type = response.headers["content-type"] - - LastWrite = datetime(2020, 5, 17) - if exists(InstallDir + "/" + ExecutableName): - LastWrite = datetime.utcfromtimestamp( - pathlib.Path(InstallDir + "/" + ExecutableName).stat().st_mtime - ) - - # update checks - - if(GAME == "jak1"): - NotExtracted = bool(not (exists(UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP"))) - NotCompiled = bool(not (exists(InstallDir + r"\data\out\jak1\fr3\GAME.fr3"))) - needUpdate = bool((LastWrite < LatestRel) or (NotExtracted) or NotCompiled) - if(GAME == "jak2"): - NotExtracted = bool(not (exists(UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP"))) - NotCompiled = bool(not (exists(InstallDir + r"\data\out\jak2\fr3\GAME.fr3"))) - needUpdate = bool((LastWrite < LatestRel) or (NotExtracted) or NotCompiled) - - print("Currently installed version created on: " + LastWrite.strftime('%Y-%m-%d %H:%M:%S')) - print("Newest version created on: " + LatestRel.strftime('%Y-%m-%d %H:%M:%S')) - if(NotExtracted): - print("Error! Iso data does not appear to be extracted to " + UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP") - print("Will ask user to provide ISO") - if(NotCompiled): - print("Error! The game is not compiled") - if((LastWrite < LatestRel)): - print("Looks like we need to download a new update!") - print(LastWrite) - print(LatestRel) - print("Is newest posted update older than what we have installed? " + str((LastWrite < LatestRel))) - - if(GAME == "jak1"): - # attempt to migrate any old settings files from using MOD_NAME to MOD_ID - if exists(AppdataPATH + "\OpenGOAL\jak1\settings\\" + MOD_NAME + "-settings.gc"): - # just to be safe delete the migrated settings file if it already exists (shouldn't happen but prevents rename from failing below) - if exists(AppdataPATH + "\OpenGOAL\jak1\settings\\" + MOD_ID + "-settings.gc"): - os.remove( - AppdataPATH + "\OpenGOAL\jak1\settings\\" + MOD_ID + "-settings.gc" - ) - - # rename settings file - os.rename( - AppdataPATH + "\OpenGOAL\jak1\settings\\" + MOD_NAME + "-settings.gc", - AppdataPATH + "\OpenGOAL\jak1\settings\\" + MOD_ID + "-settings.gc", - ) - # force update to ensure we recompile with adjusted settings filename in pckernel.gc - needUpdate = True - - if (needUpdate): - - #start the actual update method if needUpdate is true - print("\nNeed to update") - print("Starting Update...") - # Close Gk and goalc if they were open. - try_kill_process("gk.exe") - try_kill_process("goalc.exe") - - # download update from github - # Create a new directory because it does not exist - try_remove_dir(InstallDir + "/temp") - if not os.path.exists(InstallDir + "/temp"): - print("Creating install dir: " + InstallDir) - os.makedirs(InstallDir + "/temp") - - response = requests.get(LatestRelAssetsURL) - if response.history: - print("Request was redirected") - for resp in response.history: - print(resp.status_code, resp.url) - print("Final destination:") - print(response.status_code, response.url) - LatestRelAssetsURL = response.url - - else: - print("Request was not redirected") - - print("Downloading update from " + LatestRelAssetsURL) - file = urllib.request.urlopen(LatestRelAssetsURL) - print() - print(str("File size is ") + str(file.length)) - urllib.request.urlretrieve( - LatestRelAssetsURL, InstallDir + "/temp/updateDATA.zip", show_progress - ) - print("Done downloading") - r = requests.head(LatestRelAssetsURL, allow_redirects=True) - - # delete any previous installation - print("Removing previous installation " + InstallDir) - try_remove_dir(InstallDir + "/data") - try_remove_dir(InstallDir + "/.github") - try_remove_file(InstallDir + "/gk.exe") - try_remove_file(InstallDir + "/goalc.exe") - try_remove_file(InstallDir + "/extractor.exe") - try_remove_file(InstallDir + "/decompiler.exe") - - - #if ISO_DATA has content, store this path to pass to the extractor - if (exists(UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP")): - - print("We found ISO data from a previous mod installation! Lets use it!") - print("Found in " + UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP") - iso_path = UniversalIsoPath + "\\" +GAME - else: - #if ISO_DATA is empty, prompt for their ISO and store its path. - - #cleanup and remove a corrupted iso - if os.path.exists(UniversalIsoPath + "\\" + GAME) and os.path.isdir(UniversalIsoPath + "\\" + GAME): - print("Removing corrupted iso destination... " + UniversalIsoPath + "\\" + GAME + "") - shutil.rmtree(UniversalIsoPath + "\\" + GAME) - print("corrupt iso removed.") - - print("Looking for some ISO data in " + UniversalIsoPath + "\\" +GAME) - - print("We did not find ISO data from a previous mod, lets ask for some!") - # prompt for ISO file - root = tk.Tk() - root.title("Select ISO") - root.geometry("230x1") - - top_level = tk.Toplevel(root) - top_level.attributes("-topmost", True) # Set the file dialog to stay on top - - iso_path = filedialog.askopenfilename(parent=top_level) - root.destroy() - if pathlib.Path(iso_path).is_file: - if not (pathlib.Path(iso_path).suffix).lower() == ".iso": - 1 / 0 - # extract update - print("Extracting update") - TempDir = InstallDir + "/temp" - with zipfile.ZipFile(TempDir + "/updateDATA.zip", "r") as zip_ref: - zip_ref.extractall(TempDir) - - # delete the update archive - try_remove_file(TempDir + "/updateDATA.zip") - - SubDir = TempDir - if LINK_TYPE == githubUtils.LinkTypes.BRANCH or len(os.listdir(SubDir)) == 1: - # for branches, the downloaded zip puts all files one directory down - SubDir = SubDir + "/" + os.listdir(SubDir)[0] - - print("Moving files from " + SubDir + " up to " + InstallDir) - allfiles = os.listdir(SubDir) - for f in allfiles: - shutil.move(SubDir + "/" + f, InstallDir + "/" + f) - try_remove_dir(TempDir) - - if(GAME=="jak1"): - replaceText( - InstallDir + r"\data\goal_src\jak1\pc\pckernel.gc", - "Playing Jak and Daxter: The Precursor Legacy", - "Playing " + MOD_NAME, - ) - replaceText( - InstallDir + r"\data\goal_src\jak1\pc\pckernel.gc", - "/pc-settings.gc", - r"/" + MOD_ID + "-settings.gc", - ) - - # if extractOnUpdate is True, check their ISO_DATA folder - - # Close Gk and goalc if they were open. - try_kill_process("gk.exe") - try_kill_process("goalc.exe") - print("Done update starting extractor This one can take a few moments! \n") - - #extract and compile, but dont boot the game so we can move the iso files - - if(GAME == "jak1"): - extractor_command_list = [InstallDir + "\extractor.exe", "-f", iso_path , "-e", "-v", "-d", "-c"] - print(extractor_command_list) - subprocess.Popen(extractor_command_list, shell=True, cwd=os.path.abspath(InstallDir)) - - # move the extrated contents to the universal launchers directory for next time. - - while process_exists("extractor.exe"): - print("extractor.exe still running, sleeping for 1s") - time.sleep(1) - - if(GAME == "jak2"): - decompiler_command_list = [InstallDir + "\decompiler.exe", - "./data/decompiler/config/jak2/jak2_config.jsonc", - iso_path, - "./data/decompiler_out", - "--version" - "\"ntsc_v1\"", - "--config-override", - "{\"decompile_code\": false}"] - print(decompiler_command_list) - subprocess.Popen(decompiler_command_list, shell=True, cwd=os.path.abspath(InstallDir)) - - # move the extrated contents to the universal launchers directory for next time. - if not (exists((UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP"))): - while process_exists("decompiler.exe"): - print("decompiler.exe still running, sleeping for 1s") - time.sleep(1) - - - if not os.path.exists(UniversalIsoPath + "\\" + GAME): - shutil.move(InstallDir + "/data/iso_data"+ "\\" + GAME, UniversalIsoPath) - print("copying " + InstallDir + "/data/iso_data"+ "\\" + GAME + "to " + UniversalIsoPath ) - - #keep checking to make sure the move is in a finished state - while not (exists((UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP"))): - print("waiting for iso at " + UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP") - time.sleep(1) - - if(NotExtracted): - print("Error! Iso data does not appear to be extracted to " + UniversalIsoPath + "\\" + GAME + "\Z6TAIL.DUP") - print("Will ask user to provide ISO") - if(NotCompiled): - print("Error! The game is not compiled") - if((LastWrite < LatestRel)): - print("Looks like we need to download a new update!") - print(LastWrite) - print(LatestRel) - print("Is newest posted update older than what we have installed? " + str((LastWrite < LatestRel))) - - #ok launch game :D - subprocess.Popen(GKCOMMANDLINElist, shell=True, cwd=os.path.abspath(InstallDir)) - - else: - # if we dont need to update, then close any open instances of the game and just launch it - print("Game is up to date!") - print("Launching now!") - launch_local(MOD_ID, GAME)