@@ -59,6 +59,7 @@ def __init__(self, master):
5959 self .expecting_player_list_next_line = False
6060 self .player_count_line_prefix = "There are "
6161 self .player_count_line_suffix = " players online:"
62+ self .psutil_proc = None
6263
6364 # --- TK Variables ---
6465 self .master = master
@@ -1200,7 +1201,10 @@ def _create_resources_view_widgets(self, parent_frame):
12001201 self .cpu_percent_label .pack (side = tk .LEFT , expand = True )
12011202
12021203 def _update_resource_usage (self ):
1203- if not hasattr (self , 'server_handler' ) or not self .server_handler .is_running ():
1204+ is_running = hasattr (self , 'server_handler' ) and self .server_handler .is_running ()
1205+
1206+ if not is_running :
1207+ self .psutil_proc = None # Reset process cache when server is off
12041208 if matplotlib_available and hasattr (self , 'line_cpu' ):
12051209 self .cpu_history = [0.0 ] * 50
12061210 self .ram_history = [0.0 ] * 50
@@ -1214,29 +1218,52 @@ def _update_resource_usage(self):
12141218
12151219 try :
12161220 pid = self .server_handler .get_pid ()
1217- if pid is None : return
1218- proc = psutil .Process (pid )
1219- cpu_percent = proc .cpu_percent (interval = None ) / (psutil .cpu_count () or 1 )
1220- self .cpu_history .pop (0 )
1221- self .cpu_history .append (float (cpu_percent ))
1222-
1223- mem_info = proc .memory_info ()
1221+ if pid is None :
1222+ self .psutil_proc = None
1223+ self .master .after (2000 , self ._update_resource_usage )
1224+ return
1225+
1226+ # If we don't have a process object or the PID has changed, find the correct process to monitor.
1227+ if self .psutil_proc is None or self .psutil_proc .pid != pid :
1228+ parent_proc = psutil .Process (pid )
1229+
1230+ # Search for a java child process, which is the actual server
1231+ java_proc = None
1232+ try :
1233+ children = parent_proc .children (recursive = True )
1234+ for child in children :
1235+ if child .name ().lower () in ['java.exe' , 'javaw.exe' ]:
1236+ java_proc = child
1237+ break
1238+ except psutil .NoSuchProcess :
1239+ pass # Parent process might have already died, which is fine.
1240+
1241+ self .psutil_proc = java_proc if java_proc else parent_proc
1242+ self .psutil_proc .cpu_percent (interval = None ) # Prime the measurement
1243+
1244+ # Now, get the actual usage from the correct process
1245+ cpu_percent = self .psutil_proc .cpu_percent (interval = None ) / (psutil .cpu_count () or 1 )
1246+ mem_info = self .psutil_proc .memory_info ()
12241247 ram_percent = (mem_info .rss / psutil .virtual_memory ().total ) * 100
1225- self .ram_history .pop (0 )
1226- self .ram_history .append (ram_percent )
1248+
1249+ self .cpu_history .pop (0 ); self .cpu_history .append (float (cpu_percent ))
1250+ self .ram_history .pop (0 ); self .ram_history .append (ram_percent )
12271251
12281252 if matplotlib_available and self .resource_canvas .get_tk_widget ().winfo_exists ():
12291253 self .line_cpu .set_ydata (self .cpu_history )
12301254 self .line_ram .set_ydata (self .ram_history )
1255+ self .ax_cpu .set_ylim (0 , max (10 , (max (self .cpu_history ) // 10 + 2 ) * 10 ))
1256+ self .ax_ram .set_ylim (0 , max (10 , (max (self .ram_history ) // 5 + 2 ) * 5 ))
12311257 self .resource_canvas .draw ()
12321258 self .cpu_percent_label .configure (text = f"CPU: { cpu_percent :.1f} %" )
12331259 self .ram_label .configure (text = f"RAM: { mem_info .rss / (1024 ** 2 ):.0f} MB ({ ram_percent :.1f} %)" )
12341260
1235- except (psutil .NoSuchProcess , psutil .AccessDenied ): pass
1261+ except (psutil .NoSuchProcess , psutil .AccessDenied ):
1262+ self .psutil_proc = None # Process died, clear the cache
12361263 finally :
12371264 self .master .after (2000 , self ._update_resource_usage )
12381265
1239- def log_to_console (self , msg , level = "info" ):
1266+ def _write_to_console_widgets (self , msg , level = "info" ):
12401267 text_boxes = []
12411268 if hasattr (self , 'full_console_output_area' ) and self .full_console_output_area .winfo_exists ():
12421269 text_boxes .append (self .full_console_output_area )
@@ -1247,6 +1274,8 @@ def log_to_console(self, msg, level="info"):
12471274 text_box .insert (tk .END , msg , level )
12481275 text_box .see (tk .END )
12491276
1277+ def log_to_console (self , msg , level = "info" ):
1278+ self ._write_to_console_widgets (msg , level )
12501279 self .process_server_output (msg , level )
12511280
12521281 def start_server_thread (self ):
@@ -1406,13 +1435,15 @@ def send_command_from_entry(self, event=None): self.send_command_from_button()
14061435 def send_command_from_button (self ):
14071436 cmd = self .command_entry .get ().strip ()
14081437 if cmd :
1438+ self ._write_to_console_widgets (f"> { cmd } \n " , "info" )
14091439 self .server_handler .send_command (cmd )
14101440 self .command_entry .delete (0 , tk .END )
14111441
14121442 def send_command_from_console_entry (self , event = None ): self .send_command_from_console_button ()
14131443 def send_command_from_console_button (self ):
14141444 cmd = self .console_command_entry .get ().strip ()
14151445 if cmd :
1446+ self ._write_to_console_widgets (f"> { cmd } \n " , "info" )
14161447 self .server_handler .send_command (cmd )
14171448 self .console_command_entry .delete (0 , tk .END )
14181449
@@ -1522,13 +1553,11 @@ def _refresh_players_display(self):
15221553
15231554 ctk .CTkButton (row , text = "Ban" , width = 50 , command = lambda p = player_name : self ._context_ban_player (p )).pack (side = tk .RIGHT , padx = 5 , pady = 5 )
15241555 ctk .CTkButton (row , text = "Kick" , width = 50 , command = lambda p = player_name : self ._context_kick_player (p )).pack (side = tk .RIGHT , padx = 5 , pady = 5 )
1525- op_button = ctk .CTkButton (row , text = "Op" , width = 50 , command = lambda p = player_name : self ._context_op_player (p , True ))
1526- deop_button = ctk .CTkButton (row , text = "De-Op" , width = 50 , command = lambda p = player_name : self ._context_op_player (p , False ))
15271556
15281557 if player_name in self .ops_list :
1529- deop_button .pack (side = tk .RIGHT , padx = 5 , pady = 5 )
1558+ ctk . CTkButton ( row , text = "De-Op" , width = 50 , command = lambda p = player_name : self . _context_op_player ( p , False )) .pack (side = tk .RIGHT , padx = 5 , pady = 5 )
15301559 else :
1531- op_button .pack (side = tk .RIGHT , padx = 5 , pady = 5 )
1560+ ctk . CTkButton ( row , text = "Op" , width = 50 , command = lambda p = player_name : self . _context_op_player ( p , True )) .pack (side = tk .RIGHT , padx = 5 , pady = 5 )
15321561
15331562 self ._update_dashboard_info ()
15341563
0 commit comments