Skip to main content

Overview

The profile system allows you to create multiple mod configurations and switch between them instantly. Each profile saves which mods are enabled or disabled, making it easy to maintain different setups for various purposes.

How profiles work

Profiles are independent configurations that track:
  • Mod enabled/disabled states - Each profile remembers which mods are active
  • Profile metadata - Name, description, creation date, and last modified date
  • Active profile - One profile is always active at a time
Profiles are stored as JSON files in the profiles/ directory, with each profile having a unique ID (see src/models/profile_manager_model.py:518-539).

Profile data structure

Each profile contains:
{
    "id": "unique-uuid",
    "name": "My Profile",
    "description": "Optional description",
    "mods": {
        "mod_name_1": {"enabled": true},
        "mod_name_2": {"enabled": false}
    },
    "created_at": "2024-01-15T10:30:00",
    "updated_at": "2024-01-20T15:45:00",
    "active": true
}

Default profile

BD2 Mod Manager creates a Default profile automatically on first launch. This profile:
  • Cannot be deleted
  • Serves as the standard profile for managing mods
  • Is automatically created if corrupted or missing
The default profile creation is handled in src/models/profile_manager_model.py:396-414:
def _create_default_profile(self) -> None:
    """Loads the default profile or creates it if it doesn't exist or is corrupt."""
    default_path = self._profiles_folder / "default.json"
    if default_path.exists():
        try:
            with default_path.open("r", encoding="utf-8") as f:
                profile = Profile.from_dict(json.load(f))
                # ...
        except (json.JSONDecodeError, ValueError) as e:
            logger.error(f"Default profile is corrupt: {e}. A new one will be created.")
    
    default_profile = Profile(id="default", _name="Default", 
                             _description="The standard profile for managing mods.")

Creating profiles

1

Open profile manager

Click the Profiles button or menu option in the mod manager.
2

Create new profile

Click New Profile or the + button.
3

Name your profile

Enter a unique name for your profile (e.g., “PvP Setup”, “Story Mode”, “Favorite Characters”).
Profile names must be unique. The manager prevents duplicate names.
4

Add description (optional)

Provide a description to help you remember what this profile is for.
5

Configure mods

Enable or disable mods as needed. Your selections are automatically saved to the profile.
Profile creation is implemented in src/models/profile_manager_model.py:442-454:
def create_profile(self, name: str, description: Optional[str] = None) -> Profile:
    norm_name = name.lower().strip()
    if norm_name in self._profiles_by_name:
        raise ProfileAlreadyExistsError(f"Profile with name '{name}' already exists.")
    
    profile = Profile(id=str(uuid4()), _name=name, _description=description)
    
    self.save_profile(profile)
    self._profiles[profile.id] = profile
    self._profiles_by_name[norm_name] = profile

Switching profiles

Switch between profiles to instantly change your mod configuration:
1

Open profile list

View all available profiles in the profile manager or dropdown.
2

Select a profile

Click on the profile you want to activate.
3

Automatic state update

The mod manager immediately updates to show which mods are enabled in the selected profile.
4

Sync to apply

Click Sync to apply the new mod configuration to the game.
You can switch profiles without syncing to preview which mods would be enabled, then sync when ready.
When switching profiles (see src/models/profile_manager_model.py:501-516):
  1. The previous active profile is deactivated and saved
  2. The new profile is marked as active and saved
  3. A signal is emitted to refresh the mod view
  4. All mod enabled states are updated from the new profile
This is coordinated in src/models/mod_manager_model.py:138-152:
def _on_profile_switched(self) -> None:
    self.refresh_mods_data()
    self.currentProfileChanged.emit()

def refresh_mods_data(self) -> None:
    profile = self._profile_manager.get_current_profile()
    
    for mod_name, mod_entry in self._mod_entries.items():
        if profile:
            modinfo = profile.get_mod(mod_name)
            if modinfo:
                mod_entry.enabled = modinfo.enabled
            else:
                mod_entry.enabled = False

Editing profiles

Modify profile details at any time:
  • Rename profile: Change the profile name (except for Default)
  • Update description: Modify or add a description
  • Modify mod states: Enable or disable mods in the profile
All changes are automatically saved with an updated timestamp. The updated_at field tracks when the profile was last modified (see src/models/profile_manager_model.py:117-120).

Deleting profiles

Remove profiles you no longer need:
You cannot delete:
  • The Default profile
  • The currently active profile
Switch to another profile before deleting the one you want to remove.
When you delete a profile:
  1. The profile JSON file is removed from disk
  2. The profile is removed from the manager’s cache
  3. The profile list updates automatically
Deletion validation is in src/models/profile_manager_model.py:456-476:
def delete_profile(self, profile_id: str) -> None:
    if profile_id == "default":
        raise ValueError("Cannot delete the default profile.")
    if self._current_profile and profile_id == self._current_profile.id:
        raise ProfileInUseError("Cannot delete the currently active profile.")
    
    profile = self._profiles.get(profile_id)
    if not profile:
        raise ProfileNotFoundError(f"Profile with ID '{profile_id}' not found.")

Profile metadata

Each profile tracks useful metadata:

Timestamps

  • created_at: When the profile was created
  • updated_at: Last modification time (automatically updated)

Mod counts

  • Total mods: Number of mods tracked in the profile
  • Enabled mods: Number of currently enabled mods
You can view this information in the profile details view. Mod counts are calculated dynamically (see src/models/profile_manager_model.py:108-115):
@property
def mod_count(self) -> int:
    """Return the total number of mods in this profile."""
    return len(self.mods)

@property
def enabled_mod_count(self) -> int:
    """Return the number of enabled mods in this profile."""
    return sum(1 for mod in self.mods.values() if mod.enabled)

Use cases

Profiles are perfect for different scenarios:

Character-focused profiles

Create profiles for your favorite characters:
  • “Angelica Mods” - Only Angelica character mods
  • “Swimsuit Characters” - Seasonal costume mods
  • “Main Team” - Mods for your primary team

Content-specific profiles

  • “Story Mode” - Cutscene and dating scene mods for story enjoyment
  • “PvP Clean” - Minimal mods for competitive play
  • “Screenshot Mode” - Idle animations and special illustrations

Testing profiles

  • “Testing New Mods” - Isolated profile for trying new mods before adding to main setup
  • “Mod Development” - Profile for testing your own mod creations

Automatic profile updates

Profiles automatically stay in sync with mod operations:
  • Mod renamed: All profiles update their references to the new name
  • Mod deleted: All profiles remove the mod from their configuration
  • Mod added: New mods start as disabled in all profiles
This ensures profile integrity even when mods change (see src/models/mod_manager_model.py:389-392 for rename handling).

Profile storage

Profiles are stored as individual JSON files in the profiles/ directory:
profiles/
├── default.json
├── 550e8400-e29b-41d4-a716-446655440000.json
└── 6ba7b810-9dad-11d1-80b4-00c04fd430c8.json
Each file contains the complete profile data and can be backed up or shared with other users.
You can manually backup your profiles by copying the profiles/ directory to a safe location.

Build docs developers (and LLMs) love