@@ -119,18 +119,32 @@ def __init__(self, root):
119119 def load_config (self ):
120120 if os .path .exists (CONFIG_FILE ):
121121 try :
122- with open (CONFIG_FILE , 'r' ) as f : return json .load (f )
122+ with open (CONFIG_FILE , 'r' ) as f :
123+ data = json .load (f )
124+ # Convert relative paths back to absolute
125+ for key in ["game_path" , "steamcmd_path" , "cache_path" ]:
126+ if key in data and data [key ] and not os .path .isabs (data [key ]):
127+ data [key ] = os .path .normpath (os .path .join (self .base_dir , data [key ]))
128+ return data
123129 except : return {}
124130 return {}
125131
126132 def save_config (self , * args ):
133+ def make_rel (path ):
134+ if not path : return ""
135+ try :
136+ if os .path .splitdrive (path )[0 ].lower () == os .path .splitdrive (self .base_dir )[0 ].lower ():
137+ return os .path .relpath (path , self .base_dir )
138+ except : pass
139+ return path
140+
127141 config = {
128- "game_path" : self .path_var .get (),
129- "steamcmd_path" : self .steamcmd_var .get (),
130- "cache_path" : self .cache_var .get (),
142+ "game_path" : make_rel ( self .path_var .get () ),
143+ "steamcmd_path" : make_rel ( self .steamcmd_var .get () ),
144+ "cache_path" : make_rel ( self .cache_var .get () ),
131145 "use_physical" : self .use_physical_var .get ()
132146 }
133- with open (CONFIG_FILE , 'w' ) as f : json .dump (config , f )
147+ with open (CONFIG_FILE , 'w' ) as f : json .dump (config , f , indent = 4 )
134148
135149 def setup_ui (self ):
136150 style = ttk .Style ()
@@ -486,7 +500,35 @@ def ensure_steamcmd(self):
486500 raise e
487501
488502 def check_admin (self ):
489- if not ctypes .windll .shell32 .IsUserAnAdmin (): self .log ("NOTICE: Non-Admin mode detected." , "error" )
503+ if not ctypes .windll .shell32 .IsUserAnAdmin ():
504+ self .log ("NOTICE: Non-Admin mode detected." , "error" )
505+ self .show_admin_warning ()
506+
507+ def show_admin_warning (self ):
508+ self .admin_frame = tk .Frame (self .dl_tab , bg = "#330000" , pady = 2 )
509+ children = self .dl_tab .winfo_children ()
510+ if children :
511+ self .admin_frame .pack (side = "top" , fill = "x" , padx = 10 , pady = (5 ,0 ), before = children [0 ])
512+ else :
513+ self .admin_frame .pack (side = "top" , fill = "x" , padx = 10 , pady = 5 )
514+
515+ lbl = tk .Label (self .admin_frame , text = "⚠ ADMIN RIGHTS REQUIRED FOR SYMLINKS" ,
516+ bg = "#330000" , fg = "#ff5555" , font = ("Consolas" , 10 , "bold" ))
517+ lbl .pack (side = "left" , padx = 10 )
518+
519+ btn = ttk .Button (self .admin_frame , text = "RELAUNCH AS ADMIN" , command = self .relaunch_admin )
520+ btn .pack (side = "right" , padx = 5 , pady = 2 )
521+ ToolTip (lbl , "Windows requires Administrator privileges to create 'Junction' links.\n Without this, mods cannot be linked to the game folder." )
522+
523+ def relaunch_admin (self ):
524+ try :
525+ if getattr (sys , 'frozen' , False ):
526+ ctypes .windll .shell32 .ShellExecuteW (None , "runas" , sys .executable , "" , None , 1 )
527+ else :
528+ ctypes .windll .shell32 .ShellExecuteW (None , "runas" , sys .executable , f'"{ os .path .abspath (sys .argv [0 ])} "' , None , 1 )
529+ self .root .destroy ()
530+ except Exception as e :
531+ self .log (f"Relaunch failed: { e } " , "error" )
490532
491533 def browse_game (self ):
492534 p = filedialog .askdirectory ()
0 commit comments