11from tkinter import *
22from tkinter .ttk import *
33from tkinter .scrolledtext import ScrolledText
4- from tkinter import messagebox , filedialog
4+ from tkinter import messagebox , filedialog , Canvas
55from PIL import ImageTk , Image
66from urllib .request import urlretrieve
77from urllib .error import *
@@ -28,7 +28,7 @@ import socket
2828import random
2929import platform
3030
31- VERSION = "0.9 "
31+ VERSION = "0.10 "
3232
3333def send_error_report (prog , fatal = False ):
3434 try :
@@ -100,22 +100,28 @@ class App:
100100 logger .info ("AP Launcher has started, now initalizing window." )
101101 self .win = Tk ()
102102 self .win .title (f"AP Launcher v{ VERSION } " )
103+ self .win .rowconfigure (0 , weight = 1 )
104+ self .win .columnconfigure (0 , weight = 1 )
103105 self .tabs = Notebook (self .win )
104- self .tabs .grid ()
106+ self .tabs .grid (column = 0 , row = 0 , sticky = "nsew" )
107+ self .tabs .rowconfigure (0 , weight = 1 )
108+ self .tabs .columnconfigure (0 , weight = 1 )
105109 self .minecraftdir = os .path .join (os .getenv ('APPDATA' ), '.minecraft' )
106110 self .win .protocol ("WM_DESTROY_WINDOW" , lambda : self .on_closing ())
107111 self .win .protocol ("WM_DELETE_WINDOW" , lambda : self .on_closing ())
108112 self .accounts = self .get_accounts ()
109113 self .mainframe = Frame (self .win )
114+ self .mainframe .rowconfigure (0 , weight = 1 )
115+ self .mainframe .columnconfigure (0 , weight = 1 )
110116 self .tabs .add (self .mainframe , text = "Versions" , sticky = "nsew" )
111117 logger .info ("Cleaning up any leftover update files..." )
112118 if not os .path .isdir ("assets" ):
113119 os .mkdir ("assets" )
114120 if not os .path .isdir ("temp" ):
115121 os .mkdir ("temp" )
116122 try :
117- os .remove ("temp/APLauncher .exe" )
118- os .remove ("temp/launcher_process .exe" )
123+ os .remove ("APLauncher_old .exe" )
124+ os .remove ("launcher_process_old .exe" )
119125 logger .info ("Update files cleaned up." )
120126 except :
121127 logger .info ("No update files found" )
@@ -131,11 +137,13 @@ class App:
131137 except URLError :
132138 logger .info ("Unable to retrieve background and icon, using cached." )
133139 pass
134- self .background = ImageTk .PhotoImage (Image .open ("assets/background.png" ))
140+ self .background = ImageTk .PhotoImage (file = "assets/background.png" )
141+ self .win .geometry (f"{ self .background .width ()} x{ self .background .height ()} " )
135142 self .icon = ImageTk .PhotoImage (file = "assets/icon.ico" )
136143 self .win .iconphoto (True , self .icon )
137- self .background2 = Label (self .mainframe , image = self .background )
144+ self .background2 = Canvas (self .mainframe , width = self .background . width (), height = self . background . height () )
138145 self .background2 .grid (column = 0 , row = 0 , sticky = "nsew" )
146+ self .win .bind ("<Configure>" , lambda e : threading .Thread (None , target = lambda : self .resize_widgets (e )).start ())
139147 self .versionvar = StringVar ()
140148 self .get_versions ()
141149 logger .info ("Reading cache file..." )
@@ -196,10 +204,13 @@ class App:
196204 self .playcontext .entryconfigure (0 , state = "disabled" )
197205 self .playbutton .bind ("<Button-3>" , lambda x : self .do_popup (x ))
198206 self .processframe = Frame (self .win )
199- self .tabs .add (self .processframe , text = "Game Output" )
200- self .processtext = ScrolledText (self .processframe , state = "disabled" , height = 35 , width = 120 )
201- self .processtext .grid (column = 0 , row = 2 , sticky = "nsew" )
207+ self .processframe .rowconfigure (0 , weight = 1 )
208+ self .processframe .columnconfigure (0 , weight = 1 )
209+ self .tabs .add (self .processframe , text = "Game Output" , sticky = "nsew" )
210+ self .processtext = ScrolledText (self .processframe , state = "disabled" )
211+ self .processtext .grid (column = 0 , row = 0 , sticky = "nsew" )
202212 self .profileframe = Frame (self .win )
213+ self .profileframe .columnconfigure (0 , weight = 1 )
203214 self .tabs .add (self .profileframe , text = "Profiles" )
204215 self .profileselect = Frame (self .profileframe )
205216 self .profileselect .grid (column = 0 , row = 0 , sticky = "nsew" )
@@ -211,7 +222,7 @@ class App:
211222 try :
212223 self .profname = LabeledEntry (self .profileframe , "Name: " , self .accounts ["profiles" ][self .nametoprofile [self .versionvar .get ()]]["name" ])
213224 except KeyError :
214- self .profname = LabeledEntry (self .profileframe , "Name: " , "N/A " )
225+ self .profname = LabeledEntry (self .profileframe , "Name: " , "" )
215226 self .profname .grid (column = 0 , row = 1 , sticky = "nsew" )
216227 self .profgamedir = LabeledEntry (self .profileframe , "Game Directory: " , os .path .join (os .getenv ('APPDATA' ), '.minecraft' ), elength = 30 )
217228 self .profgamedir .grid (column = 0 , row = 2 , sticky = "nsew" )
@@ -225,31 +236,29 @@ class App:
225236 self .profjavargs = LabeledEntry (self .profileframe , "JVM Arguments: " , "-Xmx2G -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:G1NewSizePercent=20 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:G1HeapRegionSize=32M" , elength = 50 )
226237 self .profjavargs .grid (column = 0 , row = 4 , sticky = "nsew" )
227238 self .profsave = Button (self .profileframe , text = "Save" )
228- self .profsave .grid (column = 0 , row = 5 , sticky = "nsew " )
239+ self .profsave .grid (column = 0 , row = 5 , sticky = "w " )
229240 self .proftrans = Label (self .profileframe , text = "OR" )
230- self .proftrans .grid (column = 0 , row = 6 , sticky = "nsew " )
241+ self .proftrans .grid (column = 0 , row = 6 , sticky = "w " )
231242 self .profadd = Button (self .profileframe , text = "Import new version" , command = lambda : self .open_install_archive ())
232- self .profadd .grid (column = 0 , row = 7 , sticky = "nsew " )
243+ self .profadd .grid (column = 0 , row = 7 , sticky = "w " )
233244 self .update_profiles (self .versionvar .get ())
234245 self .profilelist .bind ("<<ComboboxSelected>>" , lambda x : self .update_profiles (self .versionvar .get ()))
235246 self .aboutpage = AboutPage (self .win )
247+ self .aboutpage .columnconfigure (0 , weight = 1 )
236248 self .tabs .add (self .aboutpage , text = "About" )
237249 logger .info ("Successfully initiated window." )
238250
251+ def resize_widgets (self , e , override = False ):
252+ if ((self .win .winfo_width () != e .width ) and (self .win .winfo_height () != e .height )) or override :
253+ self .bgfile = Image .open ("assets/background.png" )
254+ self .bgfile = self .bgfile .resize ((e .width , e .height ), Image .ANTIALIAS )
255+ self .background = ImageTk .PhotoImage (self .bgfile )
256+ self .background2 .create_image (0 , 0 , image = self .background , anchor = "nw" )
257+
239258 def kill_process (self ):
240- """Kills the running Minecraft process. I dont really know what to do about this function..."""
241- try :
242- temp = open ("temp.txt" )
243- except FileNotFoundError :
244- messagebox .showerror ("Error" , "Unable to stop the process because the process id was not loaded." )
245- return
246- try :
247- pid = int (temp .read ())
248- except :
249- messagebox .showerror ("Error" , "Unable to stop the process because the process id was corrupted." )
250- return
259+ """Kills the running Minecraft process."""
251260 try :
252- os .system (f" taskkill /pid { pid } /f" )
261+ os .system (f' taskkill /FI "WindowTitle eq Minecraft*" /T /F' )
253262 except :
254263 messagebox .showerror ("Error" , "Unable to stop the process." )
255264 return
@@ -269,9 +278,7 @@ class App:
269278 json .dump (self .accounts , open (os .path .join (self .minecraftdir , "launcher_profiles.json" ), "w" ), indent = 2 )
270279 json .dump (self .cache , open ("cache.json" , "w" ), indent = 2 )
271280 self .win .withdraw ()
272- if self .update_version ():
273- logger .info ("Update is required, setting up asynchronous update process." )
274- atexit .register (lambda : self .run_updater ())
281+ self .update_version ()
275282 sys .exit ()
276283
277284 def get_versions (self ):
@@ -423,7 +430,7 @@ class App:
423430 def update_procscreen (self , text ):
424431 """Updates the console screen"""
425432 self .processtext .config (state = "normal" )
426- self .processtext .insert ("end" , text + " \n " )
433+ self .processtext .insert ("end" , text )
427434 self .processtext .config (state = "disabled" )
428435 self .processtext .see ("end" )
429436
@@ -438,9 +445,9 @@ class App:
438445 def get_latest_version (self , type_ ):
439446 versions = [x [0 ] for x in os .walk (os .path .join (self .minecraftdir , "versions" ))]
440447 if type_ == "release" :
441- filtered = [x .split ("\\ " )[- 1 ][:6 ] for x in versions if bool (re .match ("1\.[0-9]+\.[1-9]+" , x .split ("\\ " )[- 1 ])) or bool (re .match ("1\.[0-9]+" , x .split ("\\ " )[- 1 ]))]
448+ filtered = [x .split ("\\ " )[- 1 ][:6 ] for x in versions if bool (re .match (r "1\.[0-9]+\.[1-9]+" , x .split ("\\ " )[- 1 ])) or bool (re .match (r "1\.[0-9]+" , x .split ("\\ " )[- 1 ]))]
442449 for x in range (len (filtered )):
443- if bool (re .match ("1\.[0-9]+" , filtered [x ])):
450+ if bool (re .match (r "1\.[0-9]+" , filtered [x ])):
444451 filtered [x ] += ".0"
445452 ranked = [int (x .replace ("." , "" )) for x in filtered ]
446453 if filtered [ranked .index (max (ranked ))].endswith (".0" ):
@@ -465,8 +472,22 @@ class App:
465472 return
466473 with ZipFile (open (filepath , "rb" )) as zf :
467474 folders = list (set ([os .path .dirname (x ).split ("/" )[0 ] for x in zf .namelist ()]))
468- folders .remove ("indexes" )
469- folders .remove ("natives" )
475+ try :
476+ folders .remove ("indexes" )
477+ except ValueError :
478+ pass
479+ try :
480+ folders .remove ("natives" )
481+ except ValueError :
482+ pass
483+ try :
484+ folders .remove ("libraries" )
485+ except ValueError :
486+ pass
487+ try :
488+ folders .remove ("objects" )
489+ except ValueError :
490+ pass
470491 folders .remove ("" )
471492 infofile = zf .open ("manifest.json" )
472493 info = json .load (infofile )
@@ -484,14 +505,23 @@ class App:
484505 zf .extract (file_ , os .path .join (self .minecraftdir , "versions" ))
485506 info ["profile" ][list (info ["profile" ].keys ())[0 ]]["created" ] = datetime .datetime .now ().strftime ("%Y-%m-%dT%H:%M:%S.%f" )[:- 3 ] + "Z"
486507 self .accounts ["profiles" ][list (info ["profile" ].keys ())[0 ]] = info ["profile" ][list (info ["profile" ].keys ())[0 ]]
487- logger .info ("Extracting asset indexes ..." )
508+ logger .info ("Extracting assets ..." )
488509 for file_ in zf .namelist ():
489510 if file_ .startswith ("indexes" ):
490511 zf .extract (file_ , os .path .join (self .minecraftdir , "assets" ))
512+ for file_ in zf .namelist ():
513+ if file_ .startswith ("objects" ):
514+ zf .extract (file_ , os .path .join (self .minecraftdir , "assets" ))
491515 logger .info ("Extracting required DLL files..." )
492516 for file_ in zf .namelist ():
493517 if file_ .startswith ("natives" ):
494518 zf .extract (file_ , os .path .join (self .minecraftdir , "bin" ))
519+ logger .info ("Extracting libraries..." )
520+ for file_ in zf .namelist ():
521+ if file_ .startswith ("libraries" ):
522+ if not os .path .isdir (os .path .join (self .minecraftdir , * file_ .split ("/" )[:- 1 ])):
523+ os .makedirs (os .path .join (self .minecraftdir , * file_ .split ("/" )[:- 1 ]), exist_ok = True )
524+ zf .extract (file_ , self .minecraftdir )
495525 messagebox .showinfo ("Success" , "The version was successfully imported. Restart AP Launcher to see changes." )
496526 zf .close ()
497527 return
@@ -512,7 +542,7 @@ class App:
512542 durl = asset ["browser_download_url" ]
513543 break
514544 if durl is None :
515- return False
545+ return
516546 if not os .path .isdir ("update" ):
517547 os .mkdir ("update" )
518548 urlretrieve (url = durl , filename = "update/update.zip" )
@@ -532,20 +562,16 @@ class App:
532562 f2 .close ()
533563 if hash1 .hexdigest () != hash2 .hexdigest ():
534564 logger .info ("Update found." )
535- return True
536- return False
537- else :
538- return False
539-
540- def run_updater (self ):
541- if os .path .isfile ("APLauncher.exe" ):
542- shutil .move ("APLauncher.exe" , "temp/APLauncher.exe" )
543- if os .path .isfile ("launcher_process.exe" ):
544- shutil .move ("launcher_process.exe" , "temp/launcher_process.exe" )
545- shutil .move ("update/APLauncher.exe" , "APLauncher.exe" )
546- shutil .move ("update/launcher_process.exe" , "launcher_process.exe" )
565+ if os .path .isfile ("APLauncher.exe" ):
566+ os .rename ("APLauncher.exe" , "APLauncher_old.exe" )
567+ if os .path .isfile ("launcher_process.exe" ):
568+ os .rename ("launcher_process.exe" , "launcher_process_old.exe" )
569+ shutil .move ("update/APLauncher.exe" , "APLauncher.exe" )
570+ shutil .move ("update/launcher_process.exe" , "launcher_process.exe" )
547571
548572if __name__ == "__main__" :
573+ if not os .path .isdir ("launcher_logs" ):
574+ os .mkdir ("launcher_logs" )
549575 if not os .path .isdir ("launcher_logs/gui" ):
550576 os .mkdir ("launcher_logs/gui" )
551577 if os .path .isfile ("launcher_logs/gui/latest.log" ):
0 commit comments