Made For Unreal — Docs
Quick Game Mode OverrideAPI ReferenceC++ API

Editor Subsystems (C++)

The two editor subsystems — UOverrideGameModeGameInstanceSubsystem applies the override, UOverrideGameModeUISubsystem builds the toolbar widget.

The editor module ships two subsystems:

  • UOverrideGameModeGameInstanceSubsystem — applies the override in PIE worlds and restores the original game mode on PIE end.
  • UOverrideGameModeUISubsystem — builds the level editor toolbar widget.

Both classes live under Private/, so they're implementation details rather than publicly extendable API. You shouldn't need to reference either from project code.

  • Module: QuickGameModeOverrideEditor (Editor)

UOverrideGameModeGameInstanceSubsystem

A UGameInstanceSubsystem. Spawns inside the editor's PIE GameInstance, swaps the world's DefaultGameMode on Initialize, and restores it on Deinitialize.

UCLASS()
class QUICKGAMEMODEOVERRIDEEDITOR_API UOverrideGameModeGameInstanceSubsystem
    : public UGameInstanceSubsystem
{
    GENERATED_BODY()

public:
    virtual bool ShouldCreateSubsystem(UObject* Outer) const override;
    virtual void Initialize(FSubsystemCollectionBase& Collection) override;
    virtual void Deinitialize() override;

private:
    UPROPERTY()
    TSubclassOf<AGameModeBase> OrgGameMode;
};

ShouldCreateSubsystem

return !(IsRunningCommandlet() || IsRunningCookCommandlet());

Spawns in normal editor sessions and PIE. Skipped during commandlet runs (which includes the cook commandlet) so cooking doesn't get a patched game mode.

Initialize

const UQuickGameModeOverrideSettings* Settings = GetDefault<UQuickGameModeOverrideSettings>();

if (Settings->bOverrideGameMode && Settings->OverrideGameModeClass.IsSet())
{
    if (TSubclassOf<AGameModeBase> OverrideClass = Settings->OverrideGameModeClass.GetValue())
    {
        if (UWorld* World = GetWorld())
        {
            AWorldSettings* WorldSettings = World->GetWorldSettings();
            OrgGameMode = WorldSettings->DefaultGameMode;
            WorldSettings->DefaultGameMode = OverrideClass;
        }
    }
}

Captures the world's current DefaultGameMode into OrgGameMode, then swaps in the override.

Deinitialize

if (UWorld* World = GetWorld())
{
    if (AWorldSettings* WorldSettings = World->GetWorldSettings())
    {
        if (OrgGameMode)
        {
            WorldSettings->DefaultGameMode = OrgGameMode;
            OrgGameMode = nullptr;
        }
    }
}

Restores the captured game mode if one was captured. The if (OrgGameMode) guard makes the restore a no-op when the override was disabled at PIE start.

Why a GameInstance subsystem rather than the engine subsystem?

UGameInstanceSubsystem instances are scoped to a single GameInstance — that includes the PIE GameInstance. Because the lifetime ends when PIE ends, Deinitialize is the natural place to restore the original game mode. An engine subsystem would persist for the editor session and would need its own end-of-PIE hook.


UOverrideGameModeUISubsystem

A UEditorSubsystem that owns the toolbar widget.

UCLASS()
class QUICKGAMEMODEOVERRIDEEDITOR_API UOverrideGameModeUISubsystem : public UEditorSubsystem
{
    GENERATED_BODY()

    using FOnComboBoxChange = SComboBox<TSharedPtr<FString>>::FOnSelectionChanged;

public:
    virtual void Initialize(FSubsystemCollectionBase& Collection) override;
    virtual bool ShouldCreateSubsystem(UObject* Outer) const override;

private:
    void PIELifeCycleEvent(bool, bool bBegin) const;
    void BuildToolBar();

    TSharedPtr<SWidget> ParentWidget;
};

ShouldCreateSubsystem

return !(IsRunningCommandlet() || IsRunningCookCommandlet());

Same gate as the GameInstance subsystem — no toolbar in commandlets.

Initialize

BuildToolBar();
FEditorDelegates::BeginPIE.AddUObject(this, &UOverrideGameModeUISubsystem::PIELifeCycleEvent, true);
FEditorDelegates::EndPIE.AddUObject(this, &UOverrideGameModeUISubsystem::PIELifeCycleEvent, false);

Builds the toolbar widget once, then registers PIE lifecycle hooks.

BuildToolBar

Extends LevelEditor.LevelEditorToolBar.User with a single composite entry containing:

  • A vertical separator.
  • An SCheckBox bound to bOverrideGameMode, with OnCheckStateChanged writing through to the settings and calling SaveDefault().
  • An SClassPropertyEntryBox filtered to AGameModeBase. The picker is disabled when the checkbox is unchecked (IsEnabled_Lambda reads the bool back from settings). On selection it writes the class through OverrideGameModeClass and calls SaveDefault(). Picking None resets the optional.
  • A trailing vertical separator.

The widget root (SBorder) is captured into ParentWidget so PIE visibility hooks can collapse / restore it.

PIELifeCycleEvent

ParentWidget->SetVisibility(bBegin ? EVisibility::Collapsed : EVisibility::Visible);

Collapses the widget when PIE begins, restores it when PIE ends. This avoids accidental edits during play.


Spawn order summary

SubsystemSpawned inPurpose
UOverrideGameModeUISubsystemEditor (not commandlets)Builds the toolbar widget.
UOverrideGameModeGameInstanceSubsystemEvery GameInstance (not commandlets)Patches PIE worlds and restores on PIE end.

The plugin is editor-only by design — there is no runtime subsystem that activates in packaged builds.