From 0d39f577f2e0d49254db970da14bbe23ac0906ba Mon Sep 17 00:00:00 2001 From: DrapBS <260050423+DrapBS@users.noreply.github.com> Date: Sat, 14 Feb 2026 09:07:30 +0000 Subject: [PATCH] [ci] apply-plugin-metadata-and-formatting --- plugins/utilities.json | 14 ++ plugins/utilities/players_list.py | 342 +++++++++++++++--------------- 2 files changed, 187 insertions(+), 169 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 2d97a60..e13632d 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -2407,6 +2407,20 @@ "md5sum": "5082acb27f3dbe701d8bd42d8948b352" } } + }, + "players_list": { + "description": "A plugin that shows you live players list", + "external_url": "https://m.youtube.com/drap_bs", + "authors": [ + { + "name": "Drap", + "email": "mrunittest@gmail.com", + "discord": "drap_bs" + } + ], + "versions": { + "1.7.0": null + } } } } \ No newline at end of file diff --git a/plugins/utilities/players_list.py b/plugins/utilities/players_list.py index 37afb8e..82c62ec 100644 --- a/plugins/utilities/players_list.py +++ b/plugins/utilities/players_list.py @@ -38,32 +38,34 @@ PLAYERS_ICON = "" class ColorPickerWindow: """Advanced color picker with custom RGB and preset colors""" - + # Preset colors grid (4 rows × 8 columns = 32 colors) PRESET_COLORS = [ # Row 1 - Reds to Greens - [(1.2, 0.0, 0.0), (0.65, 0.0, 0.0), (1.2, 0.8, 0.0), (0.89, 0.59, 0.0), (0.67, 1.0, 0.0), (0.52, 0.78, 0.0), (0.0, 1.2, 0.0), (0.0, 0.78, 0.0)], + [(1.2, 0.0, 0.0), (0.65, 0.0, 0.0), (1.2, 0.8, 0.0), (0.89, 0.59, 0.0), + (0.67, 1.0, 0.0), (0.52, 0.78, 0.0), (0.0, 1.2, 0.0), (0.0, 0.78, 0.0)], # Row 2 - Cyans to Purples - [(0.0, 1.2, 0.8), (0.0, 0.78, 0.52), (0.0, 0.8, 1.2), (0.0, 0.52, 0.78), (0.0, 0.0, 1.2), (0.0, 0.0, 0.78), (0.8, 0.0, 1.2), (0.52, 0.0, 0.78)], + [(0.0, 1.2, 0.8), (0.0, 0.78, 0.52), (0.0, 0.8, 1.2), (0.0, 0.52, 0.78), + (0.0, 0.0, 1.2), (0.0, 0.0, 0.78), (0.8, 0.0, 1.2), (0.52, 0.0, 0.78)], # Row 3 - Browns/Tans [(1.0, 0.82, 0.48), (0.8, 0.62, 0.28), (0.8, 0.8, 0.0), (0.55, 0.55, 0.0)], ] - + def __init__(self, callback, parent_window): self._callback = callback self._parent = parent_window self._width = 1100 self._height = 750 - + # Current RGB values self._r = 1.25 self._g = 1.25 self._b = 1.25 - + # Load saved colors from config cfg = babase.app.config self._saved_colors = cfg.get('Players Display - Saved Colors', []) - + self._root_widget = cw( parent=gsw('overlay_stack'), size=(self._width, self._height), @@ -71,7 +73,7 @@ class ColorPickerWindow: stack_offset=(250.0, -11.0), color=(0.25, 0.25, 0.25) ) - + # ═══════════════════════════════════════════════════ # LEFT SECTION - Custom Color Creator # ═══════════════════════════════════════════════════ @@ -82,7 +84,7 @@ class ColorPickerWindow: color=(0.25, 0.25, 0.25), root_selectable=True ) - + # "Custom" title tw( parent=self._root_widget, @@ -92,7 +94,7 @@ class ColorPickerWindow: color=(0.75, 0.75, 0.75), scale=1.65 ) - + # ═══ RGB Color Displays ═══ # Red display self._red_display = bw( @@ -104,7 +106,7 @@ class ColorPickerWindow: color=(self._r, 0, 0), enable_sound=False ) - + # Green display self._green_display = bw( parent=self._root_widget, @@ -115,7 +117,7 @@ class ColorPickerWindow: color=(0, self._g, 0), enable_sound=False ) - + # Blue display self._blue_display = bw( parent=self._root_widget, @@ -126,7 +128,7 @@ class ColorPickerWindow: color=(0, 0, self._b), enable_sound=False ) - + # Preview display (gray box) self._preview_display = bw( parent=self._root_widget, @@ -137,7 +139,7 @@ class ColorPickerWindow: color=(self._r, self._g, self._b), enable_sound=False ) - + # ═══ RGB Control Buttons ═══ # RED controls bw( @@ -151,7 +153,7 @@ class ColorPickerWindow: color=(0.15, 0.1, 0.1), on_activate_call=lambda: self._adjust_color('r', 0.05) ) - + bw( parent=self._root_widget, position=(-208.4, 599.3), @@ -163,7 +165,7 @@ class ColorPickerWindow: textcolor=(0.75, 0, 0), on_activate_call=lambda: self._adjust_color('r', -0.05) ) - + # GREEN controls bw( parent=self._root_widget, @@ -176,7 +178,7 @@ class ColorPickerWindow: color=(0.1, 0.15, 0.1), on_activate_call=lambda: self._adjust_color('g', 0.05) ) - + bw( parent=self._root_widget, position=(-208.4, 509.3), @@ -188,7 +190,7 @@ class ColorPickerWindow: textcolor=(0, 0.75, 0), on_activate_call=lambda: self._adjust_color('g', -0.05) ) - + # BLUE controls bw( parent=self._root_widget, @@ -201,7 +203,7 @@ class ColorPickerWindow: color=(0.1, 0.1, 0.15), on_activate_call=lambda: self._adjust_color('b', 0.05) ) - + bw( parent=self._root_widget, position=(-208.4, 418.3), @@ -213,7 +215,7 @@ class ColorPickerWindow: textcolor=(0, 0, 0.75), on_activate_call=lambda: self._adjust_color('b', -0.05) ) - + # ═══ RGB Value Displays ═══ self._r_text = tw( parent=self._root_widget, @@ -222,7 +224,7 @@ class ColorPickerWindow: text=f'{self._r:.2f}', color=(1.0, 0.0, 0.0) ) - + self._g_text = tw( parent=self._root_widget, position=(-253.5, 343.4), @@ -230,7 +232,7 @@ class ColorPickerWindow: text=f'{self._g:.2f}', color=(0.0, 1.0, 0.0) ) - + self._b_text = tw( parent=self._root_widget, position=(-153.5, 343.4), @@ -238,7 +240,7 @@ class ColorPickerWindow: text=f'{self._b:.2f}', color=(0.0, 0.0, 1.0) ) - + # ═══ Separator Lines ═══ bui.imagewidget( texture=bui.gettexture('white'), @@ -248,7 +250,7 @@ class ColorPickerWindow: parent=self._root_widget, color=(0.4, 0.4, 0.4) ) - + bui.imagewidget( texture=bui.gettexture('white'), opacity=0.6, @@ -257,7 +259,7 @@ class ColorPickerWindow: parent=self._root_widget, color=(0.4, 0.4, 0.4) ) - + bui.imagewidget( texture=bui.gettexture('white'), opacity=0.2, @@ -265,7 +267,7 @@ class ColorPickerWindow: size=(4.0, 52.0), parent=self._root_widget ) - + # ═══ Action Buttons ═══ # Save button bw( @@ -278,7 +280,7 @@ class ColorPickerWindow: color=(0.0, 0.89, 0.0), on_activate_call=self._save_color ) - + # Apply button bw( parent=self._root_widget, @@ -290,7 +292,7 @@ class ColorPickerWindow: color=(0.0, 0.89, 0.0), on_activate_call=self._apply_custom_color ) - + # ═══ Saved Colors Section ═══ tw( parent=self._root_widget, @@ -300,7 +302,7 @@ class ColorPickerWindow: color=(0.65, 0.65, 0.65), scale=1.2 ) - + self._saved_scroll = bui.hscrollwidget( parent=self._root_widget, position=(-487.9, 63.4), @@ -308,11 +310,11 @@ class ColorPickerWindow: capture_arrows=True, border_opacity=1.2 ) - + # ═══════════════════════════════════════════════════ # RIGHT SECTION - Preset Colors # ═══════════════════════════════════════════════════ - + # "Colors" title tw( parent=self._root_widget, @@ -322,7 +324,7 @@ class ColorPickerWindow: color=(0.75, 0.75, 0.75), scale=1.65 ) - + tw( parent=self._root_widget, position=(273.2, 702.5), @@ -331,7 +333,7 @@ class ColorPickerWindow: color=(0.55, 0.55, 0.55), scale=0.875 ) - + # Separator line bui.imagewidget( texture=bui.gettexture('white'), @@ -341,7 +343,7 @@ class ColorPickerWindow: parent=self._root_widget, color=(0.4, 0.4, 0.4) ) - + bui.imagewidget( texture=bui.gettexture('white'), opacity=0.2, @@ -349,10 +351,10 @@ class ColorPickerWindow: size=(7.5, 87.5), parent=self._root_widget ) - + # Preset colors grid self._create_preset_colors() - + # "More Colors Soon...." text tw( parent=self._root_widget, @@ -362,14 +364,14 @@ class ColorPickerWindow: color=(0.32, 0.32, 0.32), shadow=False ) - + # Loading spinner bui.spinnerwidget( parent=self._root_widget, position=(554.3, 323.2), size=45.0 ) - + # Back button (top left corner) bw( parent=self._root_widget, @@ -381,24 +383,24 @@ class ColorPickerWindow: text_scale=1.5, on_activate_call=self._close ) - + # Load saved colors self._load_saved_colors() - + cw(edit=self._root_widget, on_cancel_call=self._close) - + def _load_saved_colors(self): """Load and display saved colors from config""" if not self._saved_colors: return - + # Create container for saved colors self._saved_container = bui.containerwidget( parent=self._saved_scroll, size=(max(1000, len(self._saved_colors) * 70), 100), background=False ) - + # Add all saved color buttons for idx, color in enumerate(self._saved_colors): x_pos = idx * 70 @@ -411,22 +413,22 @@ class ColorPickerWindow: color=color, on_activate_call=lambda c=color: self._select_saved_color(c) ) - + def _create_preset_colors(self): """Create preset color buttons grid""" # Starting positions start_x = 88.1 button_size = 80.0 spacing = 20.0 - + row_positions = [589.1, 499.1, 409.1] - + for row_idx, row_colors in enumerate(self.PRESET_COLORS): y = row_positions[row_idx] - + for col_idx, color in enumerate(row_colors): x = start_x + col_idx * (button_size + spacing) - + bw( parent=self._root_widget, position=(x, y), @@ -436,7 +438,7 @@ class ColorPickerWindow: color=color, on_activate_call=lambda c=color: self._select_preset_color(c) ) - + def _adjust_color(self, channel: str, amount: float): """Adjust RGB values""" if channel == 'r': @@ -445,35 +447,35 @@ class ColorPickerWindow: self._g = max(0.0, min(1.5, self._g + amount)) elif channel == 'b': self._b = max(0.0, min(1.5, self._b + amount)) - + self._update_displays() bui.getsound('click01').play() - + def _update_displays(self): """Update all color displays""" # Update individual color displays bw(edit=self._red_display, color=(self._r, 0, 0)) bw(edit=self._green_display, color=(0, self._g, 0)) bw(edit=self._blue_display, color=(0, 0, self._b)) - + # Update preview bw(edit=self._preview_display, color=(self._r, self._g, self._b)) - + # Update RGB text displays tw(edit=self._r_text, text=f'{self._r:.2f}') tw(edit=self._g_text, text=f'{self._g:.2f}') tw(edit=self._b_text, text=f'{self._b:.2f}') - + def _save_color(self): """Save current color to saved list""" current_color = (self._r, self._g, self._b) self._saved_colors.append(current_color) - + # Save to config cfg = babase.app.config cfg['Players Display - Saved Colors'] = self._saved_colors cfg.commit() - + # Create container for saved colors if doesn't exist if not hasattr(self, '_saved_container'): self._saved_container = bui.containerwidget( @@ -481,10 +483,10 @@ class ColorPickerWindow: size=(1000, 100), background=False ) - + # Add color button in horizontal line x_pos = (len(self._saved_colors) - 1) * 70 # 70 = button width + spacing - + saved_btn = bw( parent=self._saved_container, position=(x_pos, 10), @@ -494,46 +496,46 @@ class ColorPickerWindow: color=current_color, on_activate_call=lambda c=current_color: self._select_saved_color(c) ) - + bui.screenmessage('Saved!', color=(0, 1, 0)) bui.getsound('cashRegister').play() - + def _select_saved_color(self, color: tuple): """Select a saved color and apply it""" # Update custom RGB values self._r, self._g, self._b = color self._update_displays() - + # Apply the color self._callback(color) bui.screenmessage('Applied!', color=(0, 1, 0)) bui.getsound('ding').play() - + def _apply_custom_color(self): """Apply the custom RGB color (don't close)""" self._callback((self._r, self._g, self._b)) bui.screenmessage('Applied!', color=(0, 1, 0)) bui.getsound('dingSmall').play() - + def _select_preset_color(self, color: tuple): """Select a preset color and close the window""" self._callback(color) self._close() # Close the window after selecting - + def _close(self): cw(edit=self._root_widget, transition='out_scale') class SettingsWindow: """Main settings window with live preview""" - + # Design styles DESIGNS = ['box', 'simple', 'minimal'] - + def __init__(self, source_widget=None): self._width = 1150 self._height = 700 - + # Get current settings cfg = babase.app.config self._temp_show_full = cfg.get('Players Display - Show Full Name', False) @@ -542,7 +544,7 @@ class SettingsWindow: self._temp_rainbow = cfg.get('Players Display - Rainbow', False) self._temp_show_id = cfg.get('Players Display - Show Client ID', True) self._temp_style = cfg.get('Players Display - Style', 'box') - + self._root_widget = cw( parent=gsw('overlay_stack'), size=(self._width, self._height), @@ -550,11 +552,11 @@ class SettingsWindow: stack_offset=(-250.0, -20.0), color=(0.25, 0.25, 0.25) ) - + # ═══════════════════════════════════════════════════ # HEADER # ═══════════════════════════════════════════════════ - + # Back button bw( parent=self._root_widget, @@ -567,7 +569,7 @@ class SettingsWindow: scale=0.75, on_activate_call=self._close ) - + # Settings title tw( parent=self._root_widget, @@ -577,7 +579,7 @@ class SettingsWindow: color=(0.75, 0.75, 0.75), scale=2 ) - + tw( parent=self._root_widget, position=(318.3, 651.9), @@ -587,7 +589,7 @@ class SettingsWindow: scale=0.85, shadow=0.4 ) - + # Apply button bw( parent=self._root_widget, @@ -598,22 +600,22 @@ class SettingsWindow: textcolor=(1, 1, 1), on_activate_call=self._apply_changes ) - + # ═══════════════════════════════════════════════════ # MAIN SCROLL AREA # ═══════════════════════════════════════════════════ - + scroll = sw( parent=self._root_widget, position=(86.8, 61.7), size=(1000.0, 569.0), border_opacity=1.25 ) - + # ═══════════════════════════════════════════════════ # SHOW PLAYER SECTION # ═══════════════════════════════════════════════════ - + tw( parent=self._root_widget, position=(111.4, 581.4), @@ -622,7 +624,7 @@ class SettingsWindow: scale=1.25, color=(0.85, 0.85, 0.85) ) - + # Separator line bui.imagewidget( texture=bui.gettexture('white'), @@ -631,7 +633,7 @@ class SettingsWindow: size=(975.0, 4.0), parent=self._root_widget ) - + # Name type label tw( parent=self._root_widget, @@ -643,7 +645,7 @@ class SettingsWindow: v_align='center', scale=0.8 ) - + # Popup menu for name type selection PopupMenu( parent=self._root_widget, @@ -653,7 +655,7 @@ class SettingsWindow: on_value_change_call=self._set_name_type, button_size=(185, 45) ) - + # Vertical separator 1 bui.imagewidget( texture=bui.gettexture('white'), @@ -662,7 +664,7 @@ class SettingsWindow: size=(4.0, 90.0), parent=self._root_widget ) - + # Full Name checkbox (shows both names) cbw( parent=self._root_widget, @@ -675,7 +677,7 @@ class SettingsWindow: value=self._temp_show_full, on_value_change_call=self._on_full_name_change ) - + # Vertical separator 2 bui.imagewidget( texture=bui.gettexture('white'), @@ -684,7 +686,7 @@ class SettingsWindow: size=(4.0, 90.0), parent=self._root_widget ) - + # Client ID checkbox cbw( parent=self._root_widget, @@ -697,11 +699,11 @@ class SettingsWindow: value=self._temp_show_id, on_value_change_call=self._on_client_id_change ) - + # ═══════════════════════════════════════════════════ # COLOR SECTION # ═══════════════════════════════════════════════════ - + tw( parent=self._root_widget, position=(108.3, 431.9), @@ -710,7 +712,7 @@ class SettingsWindow: color=(0.75, 0.75, 0.75), scale=1.35 ) - + # Separator line bui.imagewidget( texture=bui.gettexture('white'), @@ -719,7 +721,7 @@ class SettingsWindow: size=(975.0, 2.5), parent=self._root_widget ) - + # Color display button self._color_display = bw( parent=self._root_widget, @@ -729,7 +731,7 @@ class SettingsWindow: color=self._temp_color, enable_sound=False ) - + # Vertical separator bui.imagewidget( texture=bui.gettexture('white'), @@ -738,7 +740,7 @@ class SettingsWindow: size=(5.0, 80.0), parent=self._root_widget ) - + # Pick button bw( parent=self._root_widget, @@ -750,7 +752,7 @@ class SettingsWindow: textcolor=(0.9, 0.9, 1), on_activate_call=self._open_color_picker ) - + # Vertical separator bui.imagewidget( texture=bui.gettexture('white'), @@ -759,7 +761,7 @@ class SettingsWindow: size=(5.0, 80.0), parent=self._root_widget ) - + # Rainbow checkbox cbw( parent=self._root_widget, @@ -772,11 +774,11 @@ class SettingsWindow: value=self._temp_rainbow, on_value_change_call=self._on_rainbow_change ) - + # ═══════════════════════════════════════════════════ # DESIGN SECTION # ═══════════════════════════════════════════════════ - + tw( parent=self._root_widget, position=(108.3, 301.9), @@ -785,10 +787,10 @@ class SettingsWindow: color=(0.75, 0.75, 0.75), scale=1.35 ) - + # Design buttons (3 styles) self._design_btns = [] - + # Box style btn1 = bw( parent=self._root_widget, @@ -800,7 +802,7 @@ class SettingsWindow: on_activate_call=lambda: self._set_style('box') ) self._design_btns.append(btn1) - + # Simple style btn2 = bw( parent=self._root_widget, @@ -812,7 +814,7 @@ class SettingsWindow: on_activate_call=lambda: self._set_style('simple') ) self._design_btns.append(btn2) - + # Minimal style btn3 = bw( parent=self._root_widget, @@ -824,18 +826,18 @@ class SettingsWindow: on_activate_call=lambda: self._set_style('minimal') ) self._design_btns.append(btn3) - + # ═══════════════════════════════════════════════════ # RESULT SECTION (Preview) # ═══════════════════════════════════════════════════ - + result_container = cw( parent=self._root_widget, position=(1147.2, 121.9), size=(450.0, 500.0), color=(0.25, 0.25, 0.25) ) - + tw( parent=self._root_widget, position=(1328.3, 581.9), @@ -844,7 +846,7 @@ class SettingsWindow: color=(0.75, 0.75, 0.75), scale=1.55 ) - + # Preview text widget self._preview_text = tw( parent=result_container, @@ -857,22 +859,22 @@ class SettingsWindow: scale=0.5, maxwidth=400 ) - + # Start preview update loop self._update_preview() - + cw(edit=self._root_widget, on_cancel_call=self._close) - + def _generate_preview_text(self): """Generate preview text based on current settings""" player_count = 3 # Sample count - + # Get icon icon_text = f"{PLAYERS_ICON} " if PLAYERS_ICON else "" - + """Generate preview text based on current settings""" player_count = 3 # Sample count - + if self._temp_style == 'box': header = "╔═══════════════════╗\n" header += f"║ PLAYERS ({player_count}) ║\n" @@ -886,11 +888,11 @@ class SettingsWindow: else: # minimal header = f" PLAYERS ({player_count})\n\n" footer = "" - + # Sample names player_name = "YT!Drap" account_name = "Drap" - + # Build player line based on settings if self._temp_show_full: # Full name: show both @@ -901,69 +903,69 @@ class SettingsWindow: name_part = account_name else: name_part = player_name - + # Add client ID if enabled if self._temp_show_id: player_line = f" • {name_part} [#42]" else: player_line = f" • {name_part}" - + return header + player_line + footer - + def _update_preview(self): """Update preview with rainbow effect if enabled""" if not hasattr(self, '_preview_text') or not self._preview_text.exists(): return - + # Update preview text tw(edit=self._preview_text, text=self._generate_preview_text()) - + # Update color (rainbow or static) if self._temp_rainbow: # Smooth rainbow loop if not hasattr(self, '_rainbow_hue'): self._rainbow_hue = 0.0 - + self._rainbow_hue = (self._rainbow_hue + 0.02) % 1.0 color = hsv_to_rgb(self._rainbow_hue, 1.0, 1.0) tw(edit=self._preview_text, color=color) else: tw(edit=self._preview_text, color=self._temp_color) - + # Schedule next update babase.apptimer(0.05, babase.WeakCall(self._update_preview)) - + def _set_name_type(self, name_type: str): """Set name type""" self._temp_name_type = name_type - + def _set_style(self, style: str): """Set design style and update button colors""" self._temp_style = style - + # Update all design buttons for idx, btn in enumerate(self._design_btns): if self.DESIGNS[idx] == style: bw(edit=btn, color=(0.1, 1.2, 0.1)) else: bw(edit=btn, color=(0.75, 0.85, 0.75)) - + def _on_full_name_change(self, value: bool): self._temp_show_full = value - + def _on_client_id_change(self, value: bool): self._temp_show_id = value - + def _on_rainbow_change(self, value: bool): self._temp_rainbow = value - + def _on_color_selected(self, color: tuple): self._temp_color = color bw(edit=self._color_display, color=color) - + def _open_color_picker(self): ColorPickerWindow(self._on_color_selected, self) - + def _apply_changes(self): """Apply all changes and save to config""" cfg = babase.app.config @@ -974,53 +976,53 @@ class SettingsWindow: cfg['Players Display - Show Client ID'] = self._temp_show_id cfg['Players Display - Style'] = self._temp_style cfg.commit() - + bui.screenmessage('Settings Applied!', color=(0, 1, 0)) bui.getsound('cashRegister').play() - + def _close(self): cw(edit=self._root_widget, transition='out_scale') class PlayersDisplay: """Main display class""" - + def __init__(self): self.container = None self.rainbow_hue = 0.0 self.current_players = {} # Track: {client_id: (player_name, account_name)} - + def on_app_running(self): self._update_loop() - + def _update_loop(self): self._update_display() - + # Check if rainbow mode is enabled cfg = babase.app.config is_rainbow = cfg.get('Players Display - Rainbow', False) - + # Use faster loop for smooth rainbow, slower for normal updates delay = 0.05 if is_rainbow else 0.5 babase.apptimer(delay, babase.WeakCall(self._update_loop)) - + def _get_display_color(self): cfg = babase.app.config - + if cfg.get('Players Display - Rainbow', False): # Smooth rainbow loop with smaller increment self.rainbow_hue = (self.rainbow_hue + 0.01) % 1.0 return hsv_to_rgb(self.rainbow_hue, 1.0, 1.0) else: return cfg.get('Players Display - Color', (0.7, 0.7, 0.7)) - + def _show_message(self, message: str, color: tuple, duration: float = 1.0): """Show a temporary message with fade in/out animation""" try: activity = bs.get_foreground_host_activity() if activity is None: return - + with activity.context: # Create message node msg_node = bs.newnode( @@ -1039,32 +1041,32 @@ class PlayersDisplay: 'opacity': 0.0 # Start invisible } ) - + # Fade in animation (0.2 seconds) bs.animate(msg_node, 'opacity', { 0.0: 0.0, 0.2: 0.95 }) - + # Fade out animation (starts after duration) bs.animate(msg_node, 'opacity', { duration: 0.95, duration + 0.3: 0.0 }) - + # Delete node after animations complete bs.timer(duration + 0.4, msg_node.delete) - + except Exception: pass - + def _check_player_changes(self, new_players: dict): """Check for players joining or leaving new_players: {client_id: (player_name, account_name)} """ new_ids = set(new_players.keys()) old_ids = set(self.current_players.keys()) - + # Players who joined joined = new_ids - old_ids for player_id in joined: @@ -1072,7 +1074,7 @@ class PlayersDisplay: message = f"{account_name} joined the server" color = self._get_display_color() self._show_message(message, color, duration=1.0) - + # Players who left left = old_ids - new_ids for player_id in left: @@ -1080,16 +1082,16 @@ class PlayersDisplay: message = f"{player_name} left the server" color = (1.2, 0.2, 0.2) # Glowing red self._show_message(message, color, duration=1.0) - + # Update current players self.current_players = new_players.copy() - + def _update_display(self): try: activity = bs.get_foreground_host_activity() except Exception: activity = None - + if activity is None: if self.container is not None: try: @@ -1098,37 +1100,37 @@ class PlayersDisplay: pass self.container = None return - + cfg = babase.app.config show_full = cfg.get('Players Display - Show Full Name', False) name_type = cfg.get('Players Display - Name Type', 'Player Name') show_client_id = cfg.get('Players Display - Show Client ID', True) style = cfg.get('Players Display - Style', 'box') - + player_names = [] new_players_data = {} # {client_id: (player_name, account_name)} - + for p in activity.players: try: # Get both player name and account name player_name = p.getname(full=True) - + try: account_name = p.sessionplayer.inputdevice.get_v1_account_name(full=True) if not account_name: account_name = player_name except Exception: account_name = player_name - + # Get client ID try: client_id = p.sessionplayer.inputdevice.client_id except Exception: client_id = id(p) # Fallback to object id - + # Store for tracking new_players_data[client_id] = (player_name, account_name) - + # Build name based on settings if show_full: # Full name: show both names @@ -1142,7 +1144,7 @@ class PlayersDisplay: name = account_name else: name = player_name - + # Add client ID if enabled if show_client_id: try: @@ -1151,19 +1153,19 @@ class PlayersDisplay: player_names.append(f" • {name}") else: player_names.append(f" • {name}") - + except Exception: continue - + # Check for player changes (join/leave) self._check_player_changes(new_players_data) - + # Get player count player_count = len(player_names) - + # Get icon icon_text = f"{PLAYERS_ICON} " if PLAYERS_ICON else "" - + # Different styles with player count if style == 'box': header = "╔═══════════════════╗\n" @@ -1178,15 +1180,15 @@ class PlayersDisplay: else: # minimal header = f" PLAYERS ({player_count})\n\n" footer = "" - + if player_names: players_str = "\n".join(player_names) else: players_str = " ⏳ Waiting...\n No players yet" - + final_text = header + players_str + footer current_color = self._get_display_color() - + try: with activity.context: if self.container is None or not self.container.exists(): @@ -1214,12 +1216,14 @@ class PlayersDisplay: # My First Cool Mod ,WooHoo. # ba_meta export babase.Plugin + + class CoolList(babase.Plugin): """Main plugin class""" - + def __init__(self): cfg = babase.app.config - + if 'Players Display - Show Full Name' not in cfg: cfg['Players Display - Show Full Name'] = False # Default to single name if 'Players Display - Name Type' not in cfg: @@ -1232,14 +1236,14 @@ class CoolList(babase.Plugin): cfg['Players Display - Show Client ID'] = True if 'Players Display - Style' not in cfg: cfg['Players Display - Style'] = 'box' - + cfg.commit() - + self.display = PlayersDisplay() self.display.on_app_running() - + def has_settings_ui(self) -> bool: return True - + def show_settings_ui(self, source_widget: Any) -> None: SettingsWindow(source_widget)