Skip to content

Mod Organizer Plugin — Tree view for browsing & toggling mods #37

Description

@PyXiion

Origin of idea

Mod list is a flat ListView. Mods are ordered by ModsConfig.xml load order. This is correct for load-order editing, but awful for browsing a 300+ mod collection. You can't see that 12 mods are "Vanilla Factions Expanded" family, you can't bulk-toggle them, you can't organize by theme.

Needs #28 (plugin system) first

Suggestion / proposed solution

A plugin that adds a new view to the icon rail (like Steam Workshop is a separate view). It presents a virtual tree of all mods — purely for organization, navigation, and toggling. It does not affect load order in any way.

┌──────────┐  ┌────────────────────────────────────────────┐
│ Sidebar  │  │  ▼ Vanilla Factions Expanded  (12)  [✓]    │
│          │  │    ├─ Vanilla Factions Expanded - Core  [✓]│
│ ──────── │  │    ├─ Vanilla Factions Expanded - Settler [✓]│
│ All      │  │    ├─ Vanilla Factions Expanded - Medieval[✓]│
│ Active   │  │    └─ ...                                  │
│ ──────── │  │                                            │
│ Core     │  │  ▼ Combat  (8)  [◐]                        │
│ Local    │  │    ├─ Combat Extended              [✓]     │
│ Steam    │  │    ├─ Combat Extended: Armory     [✓]      │
│ ──────── │  │    ├─ Yayo's Combat 3              [☐]     │
│ Factions │  │    └─ ...                                  │
│ Combat   │  │                                            │
│ Graphics │  │  Ungrouped (3)                             │
│ ──────── │  │    ├─ EdB Prepare Carefully        [✓]     │
│ Inactive │  │    ├─ RimHUD                       [✓]     │
│ Errors   │  │    └─ ...                                  │
└──────────┘  └────────────────────────────────────────────┘

Core concepts:

  1. Folders — each mod belongs to at most one folder (enforced). A folder maps a subset of mods to a named group. In the tree, folders appear as parent nodes with a group-level checkbox (checked / partially-checked / unchecked). Toggling the folder checkbox toggles all child mods.
  2. Tags — each mod can have many tags. Tags appear in the sidebar (like provider filters) and can be used to quickly highlight/filter mods across folders. Tags are independent of folder assignment.
  3. Auto-folder rules — optional patterns that auto-assign mods to folders. E.g. packageId starts with oskarpotocki.vanillafactionsexpanded. → folder "Vanilla Factions Expanded". Rules are evaluated in order, first match wins.
  4. Ungrouped — mods not in any folder appear under an "Ungrouped" node at the bottom (toggleable).
  5. Tree does NOT touch load order. The flat ModListModel / ModList.qml remains the canonical order. The tree is purely a parallel view for browsing and bulk-toggle. Toggling a folder or a mod in the tree toggles the same ModItem.checked in the flat model.

Nested folders:

Support one additional nesting level (subfolder within a folder). Not arbitrary depth — keeps the tree manageable. Parent folder checkbox controls all descendants.

Plugin architecture:

Implemented as a plugin using the extension system (see issue #7 or the plugin's own entry_points). Consists of:
Component Type
ModTreeModel QAbstractItemModel
ModTree.qml QML
ModTreePanel Python
Folder/Tag config msgspec structs
Registers as a view (like Steam Workshop) via the plugin entry point, appears in the icon rail.

Sidebar behavior:

In the organizer view, the sidebar shows:

  • Standard filters (All, Active, Inactive, providers, errors, warnings) — works as before, filters the visible tree
  • Tag list — each user-defined tag becomes a filter entry. Click "Combat" → tree shows only mods tagged "Combat"

Operations supported:

  • Right-click mod → "Move to folder..." / "Remove from folder"
  • Right-click mod → "Manage tags..."
  • Right-click folder → "Rename", "Delete folder" (mods become ungrouped), "Sort by name"
  • Drag mod from one folder to another (within tree)
  • Create folder from selection
  • Checkbox on folder: bulk enable/disable all children
  • Search filters both the tree and the flat list identically

Storage format:

SQLite database at config_dir()/organizer.db, reusing the pattern from core/services/startup_impact_service/db.py (aiosqlite + async lock).

CREATE TABLE folders (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL UNIQUE,
    sort_order INTEGER NOT NULL DEFAULT 0,
    collapsed INTEGER NOT NULL DEFAULT 0
);

CREATE TABLE folder_mods (
    folder_id INTEGER NOT NULL REFERENCES folders(id) ON DELETE CASCADE,
    uuid TEXT NOT NULL,
    PRIMARY KEY (folder_id, uuid)
);

CREATE TABLE mod_tags (
    uuid TEXT NOT NULL,
    tag TEXT NOT NULL,
    PRIMARY KEY (uuid, tag)
);

Alternatives considered

Built-in feature instead of plugin — tied to core release cycle, harder to iterate. Plugin allows independent versioning and optional install.

  • Folders-as-tags (just tags, no exclusive folder) — loses the "one clear place" semantics that users expect from a file-tree mental model.
  • Affecting load order from the tree — conflicts with RimWorld's flat ModsConfig.xml, complicates the plugin scope. Keep load order editing in the existing flat list view.

Additional context

Depends on issue #28 (plugin/extension system) so the plugin can register a view and sidebar entries.

Tags/folders could sync with Steam collections in the future, but that's a separate enhancement.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions