Hydra Launcher

repository·main·Indexed 12 days ago

https://github.com/hydralauncher/hydra

An open-source gaming platform for managing game libraries, featuring cloud saves, achievements, and game discovery. Built with Electron, TypeScript, Python, and Rust, it includes a Python-based RPC for torrent management and a native Rust component for system process listing and image processing.

Tokens
45.6K
Snippets
121
Records
166
Agent score
96%

What's inside Hydra Launcher

  1. Overview of Hydra Launcher

    main
    Hydra Launcher is an open-source gaming platform designed to manage your gaming library. It allows users to add owned games, maintain profiles, save progress via Hydra Cloud, unlock achievements, and discover new games through a suggestion algorithm. The project is built using Node.js (Electron, React, TypeScript), Python, and Rust.
  2. Set up local development for Hydra Launcher

    main

    To build Hydra Launcher from source, you must satisfy the following environment requirements:

    • Node.js & Yarn: For the core application logic and frontend.
    • Python 3.9+: Required for the RPC layer. Install dependencies using pip install -r requirements.txt.
    • Rust toolchain: Required for the hydra-native component.

    Automatic Builds

    • The postinstall script automatically builds the Rust native addon (hydra-native/hydra-native.node).
    • Packaging scripts automatically trigger the Python RPC build.
    # Install Python dependencies
    pip install -r requirements.txt
    
    # Build for specific platforms
    yarn build:win
    yarn build:mac
    yarn build:linux
    yarn build:unpack
  3. How the Virtual Keyboard handles input and focus

    main

    The virtual keyboard operates by monitoring focus events on the document. When an isEditableTarget (defined as a non-disabled, non-readonly text input or a content-editable element) gains focus, the provider sets that element as the target.

    Key Behaviors:

    • Input Injection: When a key is pressed, the keyboard uses replaceInputSelection, backspaceInput, or insertContentEditableText to manipulate the target's value or content, ensuring compatibility with native input events.
    • Keyboard Avoidance: The keyboard supports two layout modes: floating and avoiding. If the target element is obscured by the keyboard area, the provider switches to avoiding mode and attempts to scroll the target container so the element is visible above the keyboard.
    • Navigation & Shortcuts: The keyboard integrates with gamepad inputs. For example, holding BUTTON_X performs a backspace, and LEFT_BUMPER/RIGHT_BUMPER move the cursor. It also maps specific gamepad buttons to keyboard actions like Shift (L3), Toggle Layer (R3), and Enter (RT).
  4. Disc sorting logic in DiscSelectionModal

    main

    When providing a list of discs to the DiscSelectionModal, the component automatically sorts them using the following priority:

    1. Region Order: Discs are grouped by their SKU region (e.g., US, EU, JP, KR, ASIA). The order of regions is determined by their appearance in the provided discs array.
    2. Label Numbering: Within the same region, discs are sorted numerically based on the first integer found in their label string (e.g., "Disc 1" comes before "Disc 2").

    If a disc has no SKU/region, it is placed at the end of the list.

  5. Validate Magnet URIs and Trackers

    main

    When interacting with the RPC, ensure your data adheres to these validation rules:

    • Magnet URIs: Must start with magnet:, be under 8192 characters, and contain a valid xt parameter with a urn:btih: prefix followed by a 40-character hex or 32-character Base32 hash.
    • Trackers: Must be a list of strings. Each string must be a valid URL with a scheme from the following set: http, https, udp, ws, wss.
  6. Launch the Python RPC via CLI

    main

    The Python RPC entrypoint accepts arguments via command line to configure the torrent port, RPC password, and initial download/seeding payloads. It supports three distinct argument formats:

    1. Legacy format (6 arguments): [script, torrent_port, http_port, rpc_password, initial_download, initial_seeding]
    2. Stdio format with RPC password (5 arguments): [script, torrent_port, rpc_password, initial_download, initial_seeding]
    3. Backward-compatible stdio format (4 arguments, no password): [script, torrent_port, initial_download, initial_seeding]

    Communication occurs via stdin (receiving JSON requests) and stdout (sending JSON responses).

    # Example using the Stdio format with RPC password
    python python_rpc/main.py 6881 my_secret_password '{"game_id": 1}' '[]'
  7. Use the Tabs component

    main

    The Tabs component is a highly configurable UI component for managing tabbed navigation. It supports different visual variants, gamepad navigation, and automatic scrolling for overflow content. It can be used as a controlled or uncontrolled component.

    Variants

    • default: Standard tab layout with an indicator.
    • segmented: A segmented control style where the indicator spans the background of the active tab.
    • settings: A specialized variant for settings menus, typically used with a different focus model.

    Key Features

    • Gamepad Support: Automatically handles bumper presses (LEFT_BUMPER, RIGHT_BUMPER) to switch tabs when configured.
    • Auto-scrolling: Automatically scrolls the tab list to ensure the active tab is visible in the viewport.
    • Focus Management: Can be integrated into a focus region using HorizontalFocusGroup via the manageFocusRegion prop.
    import { Tabs, type TabsItem } from './path-to-tabs';
    
    const myItems: TabsItem[] = [
      { value: 'tab1', label: 'Tab 1' },
      { value: 'tab2', label: 'Tab 2', disabled: true },
      { value: 'tab3', label: 'Tab 3' },
    ];
    
    function MyComponent() {
      const [val, setVal] = useState('tab1');
    
      return (
        <Tabs
          items={myItems}
          value={val}
          onValueChange={setVal}
          variant="default"
          selectOnFocus={true}
        />
      );
    }
  8. Configure Main process aliases and plugins

    main

    The main configuration block defines settings for the Electron main process. It includes source mapping for debugging and path aliases to simplify imports.

    Path Aliases:

    • @main: src/main
    • @locales: src/locales
    • @resources: resources
    • @shared: src/shared

    Plugins:

    • externalizeDepsPlugin(): Used to externalize dependencies.
    • swcPlugin(): Used for fast compilation via SWC.
    main: {
      build: {
        sourcemap: true,
      },
      resolve: {
        alias: {
          "@main": resolve("src/main"),
          "@locales": resolve("src/locales"),
          "@resources": resolve("resources"),
          "@shared": resolve("src/shared"),
        },
      },
      plugins: [externalizeDepsPlugin(), swcPlugin()],
    }
  9. Configure Big Picture build settings

    main

    The bigPicture configuration defines a specialized build target. It uses a specific root directory and output directory, and includes React and SVGR support.

    Key Settings:

    • root: src/big-picture
    • build.outDir: out/big-picture
    • build.rollupOptions.input: src/big-picture/index.html
    • css.postcss.plugins: Uses scopeBigPictureCss() to scope styles.

    Path Aliases:

    • @renderer: src/renderer/src
    • @locales: src/locales
    • @shared: src/shared
    bigPicture: {
      root: "src/big-picture",
      build: {
        outDir: "out/big-picture",
        rollupOptions: {
          input: resolve("src/big-picture/index.html"),
        },
      },
      css: {
        postcss: {
          plugins: [scopeBigPictureCss()],
        },
      },
      resolve: {
        alias: {
          "@renderer": resolve("src/renderer/src"),
          "@locales": resolve("src/locales"),
          "@shared": resolve("src/shared"),
        },
      },
      plugins: [svgr(), react()],
    }
  10. Configure the Tabs component props

    main

    The Tabs component accepts the following configuration options:

    PropTypeDescription
    itemsArray<TabsItem<TValue>>Required. The list of tab items to render.
    valueTValueThe currently selected tab value (for controlled mode).
    defaultValueTValueThe initial selected tab value (for uncontrolled mode).
    onValueChange(value: TValue) => voidCallback triggered when the selected tab changes.
    itemsFocusablebooleanIf false, tabs will not participate in the navigation system. Defaults to true.
    manageFocusRegionbooleanIf true, wraps the tab list in a HorizontalFocusGroup for better focus management. Defaults to true.
    selectOnFocusbooleanIf true, moving focus to a tab automatically selects it. Defaults to true.
    ignoreInitialFocusSelectionbooleanIf true, prevents the first tab from being automatically selected when the component mounts.
    animateSegmentedIndicatorbooleanEnables Framer Motion animations for the indicator in segmented variant.
    variant'default' | 'segmented' | 'settings'The visual style of the tabs.
    beforeTabsReactNodeContent rendered before the tab list.
    afterTabsReactNodeContent rendered after the tab list.
    trailingActionReactNodeContent rendered at the end of the tabs container.
    regionIdstringThe ID of the focus region if manageFocusRegion is enabled.
    navigationOverridesFocusOverridesCustom navigation behavior for the entire component.
    ariaLabelstringAccessibility label for the tab list. Defaults to 'Tabs'.
    classNamestringAdditional CSS classes for the container.