Skip to content

C++ Extension Examples

C++ recipes for adding new types and extending Operating System Simulator behavior. Pair with C++ Reference for modules/includes and the API Reference for full signatures.

All examples assume a game module with OperatingSystemSimulator in PrivateDependencyModuleNames. Add GlobalMessenger and GameplayTags when using messengers.

flowchart TB
  subgraph add["Add new types"]
    Prog["UOperatingSystemBaseProgram"]
    Cmd["UOperatingSystemTerminalCommand"]
    File["UOperatingSystemFile"]
    Mod["UOperatingSystemSettingModule"]
  end
  subgraph extend["Extend runtime"]
    OS["UOperatingSystem"]
    Statics["UOperatingSystemStatics"]
    GM["UGlobalMessageSubsystem"]
    DM["Device Messenger"]
  end
  Prog --> OS
  Cmd --> GM
  File --> Prog
  Statics --> OS
  Prog --> DM

Minimal program with validation. Assign widgets via a Blueprint child in the editor.

MyNativeProgram.h

#pragma once
#include "Programs/OperatingSystemBaseProgram.h"
#include "MyNativeProgram.generated.h"
UCLASS(Blueprintable)
class UMyNativeProgram : public UOperatingSystemBaseProgram
{
GENERATED_BODY()
public:
UMyNativeProgram();
protected:
virtual void OnValidate(FGenericError& OutError) const override;
virtual void OnStart(FGenericError& OutError) override;
virtual void OnClose(FGenericError& OutError) override;
};

MyNativeProgram.cpp

#include "MyNativeProgram.h"
UMyNativeProgram::UMyNativeProgram()
{
Name = FText::FromString(TEXT("Native Tool"));
Identifier = FName(TEXT("com.mygame.nativetool"));
Version.Major = 1;
SaveMethod = EOperatingSystemProgramSaveMethod::SaveOnExit;
}
void UMyNativeProgram::OnValidate(FGenericError& OutError) const
{
Super::OnValidate(OutError);
if (!OutError.IsValid() && WidgetClass.IsNull())
{
OutError = MAKE_ERROR(TEXT("CONFIG"), TEXT("Widget Class is required."));
}
}
void UMyNativeProgram::OnStart(FGenericError& OutError)
{
Super::OnStart(OutError);
// First frame — load state, refresh UI via program widget
}
void UMyNativeProgram::OnClose(FGenericError& OutError)
{
// Cleanup before Super if needed
Super::OnClose(OutError);
}

→ Full walkthrough: C++ program from scratch


For persistent prefs and runtime state (Mail/Banking pattern).

MyProgramSettings.h

#pragma once
#include "Programs/OperatingSystemProgramSettings.h"
#include "MyProgramSettings.generated.h"
UCLASS()
class UMyProgramSettings : public UOperatingSystemProgramSettings
{
GENERATED_BODY()
public:
UPROPERTY(SaveGame, BlueprintReadWrite, Category = "MyProgram")
int32 LastSelectedTab = 0;
UPROPERTY(SaveGame, BlueprintReadWrite, Category = "MyProgram")
FString LastOpenedPath;
};

MyProgramData.h

#pragma once
#include "Programs/OperatingSystemProgramData.h"
#include "MyProgramData.generated.h"
UCLASS()
class UMyProgramData : public UOperatingSystemProgramData
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite, Category = "MyProgram")
TArray<FString> InboxIds;
};

Wire on program constructor:

UMyNativeProgram::UMyNativeProgram()
{
SaveMethod = EOperatingSystemProgramSaveMethod::SaveOnExit;
SettingsClass = UMyProgramSettings::StaticClass();
DataClass = UMyProgramData::StaticClass();
bRequiresData = true;
}

Read at runtime:

if (UMyProgramSettings* S = Cast<UMyProgramSettings>(GetProgramSettings()))
{
S->LastSelectedTab = 2;
SaveSettings(); // when SaveMethod is SaveManually
}

#pragma once
#include "Widgets/Common/OperatingSystemProgramWidget.h"
#include "MyProgramWidget.generated.h"
class UMyNativeProgram;
UCLASS()
class UMyProgramWidget : public UOperatingSystemProgramWidget
{
GENERATED_BODY()
protected:
virtual void NativeConstruct() override;
UPROPERTY(meta = (BindWidget))
TObjectPtr<class UTextBlock> StatusText;
};
#include "MyProgramWidget.h"
#include "MyNativeProgram.h"
void UMyProgramWidget::NativeConstruct()
{
Super::NativeConstruct();
if (UMyNativeProgram* Prog = Cast<UMyNativeProgram>(GetOwningProgram()))
{
if (StatusText)
{
StatusText->SetText(Prog->GetName());
}
}
}

Set WidgetClass on the program (C++ defaults or Blueprint child).


#pragma once
#include "Programs/Terminal/OperatingSystemTerminalCommand.h"
#include "CMD_ToggleDoor.generated.h"
UCLASS()
class UCMD_ToggleDoor : public UOperatingSystemTerminalCommand
{
GENERATED_BODY()
public:
UCMD_ToggleDoor();
protected:
virtual void OnProcessCommand(const FString& Command, const bool bHasRootPermission) override;
};
#include "CMD_ToggleDoor.h"
#include "Programs/Terminal/OperatingSystemTerminal.h"
#include "GlobalMessageSubsystem.h"
#include "GameplayTagContainer.h"
UCMD_ToggleDoor::UCMD_ToggleDoor()
{
MainCommand = FName(TEXT("toggledoor"));
}
void UCMD_ToggleDoor::OnProcessCommand(const FString& Command, const bool bHasRootPermission)
{
if (UOperatingSystemTerminal* Term = ParentTerminal.Get())
{
if (const UWorld* World = Term->GetWorld())
{
if (UGlobalMessageSubsystem* MS = UGlobalMessageSubsystem::Get(*World))
{
static const FGameplayTag Tag =
FGameplayTag::RequestGameplayTag(TEXT("Message.OS.Door.Toggle"));
MS->BroadcastMessage(Tag, nullptr);
}
}
Term->AppendOutput(TEXT("Door signal sent."));
}
FinishCommand(FGenericError());
}

Register the class on your Terminal program or UOperatingSystemCmdCollection Data Asset.

Custom terminal command


#pragma once
#include "Files/OperatingSystemFile.h"
#include "MyDocumentFile.generated.h"
UCLASS()
class UMyDocumentFile : public UOperatingSystemFile
{
GENERATED_BODY()
public:
UMyDocumentFile();
protected:
virtual void OnOpen() override;
};
#include "MyDocumentFile.h"
#include "Programs/OperatingSystemBaseProgram.h"
UMyDocumentFile::UMyDocumentFile()
{
Extension = FText::FromString(TEXT(".mydoc"));
bIsDeletable = true;
bIsMovable = true;
// TargetProgramClass = UMyDocumentProgram::StaticClass(); // or set on Blueprint child
}
void UMyDocumentFile::OnOpen()
{
Super::OnOpen();
// Optional logic before target program launches
}

Spawn at runtime (from program or game code):

#include "Core/OperatingSystem.h"
#include "Core/OperatingSystemDirectory.h"
#include "Global/OperatingSystemStatics.h"
void SpawnMyDoc(UOperatingSystem* OS)
{
FGenericError Error;
if (UOperatingSystemDirectory* Desktop = UOperatingSystemStatics::GetDirectoryFromPath(
OS, TEXT("C:\\Users\\Desktop"), Error))
{
// Use OS static helpers or program methods to construct UMyDocumentFile instance
}
}

Custom file type


Override when your program owns a file extension:

void UMyDocumentProgram::OnOpenFile(UOperatingSystemFile* TargetFile, FGenericError& OutError)
{
Super::OnOpenFile(TargetFile, OutError);
if (!OutError.IsValid() && TargetFile)
{
// Cast to UMyDocumentFile, load into UI
}
}

#pragma once
#include "Programs/Settings/OperatingSystemSettingModule.h"
#include "MySettingModule.generated.h"
UCLASS()
class UMySettingModule : public UOperatingSystemSettingModule
{
GENERATED_BODY()
protected:
virtual void OnApplySetting(const FName SettingIdentifier, UObject* Payload) override;
};
void UMySettingModule::OnApplySetting(const FName SettingIdentifier, UObject* Payload)
{
Super::OnApplySetting(SettingIdentifier, Payload);
// Apply to ParentOS, broadcast via device messenger if needed
}

Register on BP_OS_SettingsSetting Modules array (duplicate BP_OS_Module_Theme as a template).

Theme module


8. Device Messenger — broadcast from C++

Section titled “8. Device Messenger — broadcast from C++”
#include "Global/OperatingSystemStatics.h"
#include "Devices/OperatingSystemDeviceMessenger.h"
void UMyMailProgram::NotifyInboxUpdated()
{
if (UOperatingSystem* OS = GetOperatingSystem())
{
if (UOperatingSystemDeviceMessenger* Messenger =
UOperatingSystemStatics::FindMessengerFromOperatingSystem(OS))
{
Messenger->Broadcast(FName(TEXT("MailReceived")), this);
}
}
}
**Listen in widget:**
```cpp
void UMyTaskbarWidget::NativeConstruct()
{
Super::NativeConstruct();
if (UOperatingSystem* OS = /* from device or program */)
{
if (auto* Messenger = UOperatingSystemStatics::FindMessengerFromOperatingSystem(OS))
{
FOperatingSystemDeviceMessageDelegate Delegate;
Delegate.BindDynamic(this, &UMyTaskbarWidget::OnMailReceived);
Messenger->BeginListening(FName(TEXT("MailReceived")), Delegate);
}
}
}

Using Device Messenger


9. Global Messenger — level actor listener

Section titled “9. Global Messenger — level actor listener”

Terminal command (see example 4) broadcasts; level actor listens:

#pragma once
#include "GameFramework/Actor.h"
#include "DoorActor.generated.h"
UCLASS()
class ADoorActor : public AActor
{
GENERATED_BODY()
protected:
virtual void BeginPlay() override;
UFUNCTION()
void OnDoorMessage(UObject* Payload);
FGameplayTag DoorTag;
};
#include "DoorActor.h"
#include "GlobalMessageSubsystem.h"
void ADoorActor::BeginPlay()
{
Super::BeginPlay();
DoorTag = FGameplayTag::RequestGameplayTag(TEXT("Message.OS.Door.Toggle"));
if (UGlobalMessageSubsystem* MS = UGlobalMessageSubsystem::Get(*GetWorld()))
{
FGlobalMessageReceiveDelegate Delegate;
Delegate.BindDynamic(this, &ADoorActor::OnDoorMessage);
MS->ListenToMessage(this, DoorTag, Delegate);
}
}
void ADoorActor::OnDoorMessage(UObject* Payload)
{
// Toggle door mesh, collision, etc.
}

Using Global Messenger


10. Filesystem — resolve path and errors

Section titled “10. Filesystem — resolve path and errors”
#include "Global/OperatingSystemStatics.h"
#include "Core/OperatingSystem.h"
#include "Core/OperatingSystemDirectory.h"
bool GetDesktopDir(UOperatingSystem* OS, UOperatingSystemDirectory*& OutDir, FGenericError& OutError)
{
OutDir = UOperatingSystemStatics::GetDirectoryFromPath(
OS, TEXT("C:\\Users\\Desktop"), OutError);
return OutDir != nullptr && !OutError.IsValid();
}

Use UOperatingSystemUnix paths (/Users/Desktop) when the active OS is Unix-type.

Filesystem operations


#include "Core/OperatingSystem.h"
void UMyProgram::NotifyComplete()
{
if (UOperatingSystem* OS = GetOperatingSystem())
{
OS->SendNotification(
FText::FromString(TEXT("Sync complete")),
FText::FromString(TEXT("All files uploaded.")),
EOperatingSystemNotificationType::Info);
}
}

Custom notifications


On your AOperatingSystemDeviceActor subclass:

void AMyDeviceActor::BeginPlay()
{
Super::BeginPlay();
// Device starts boot via UOperatingSystemBaseDevice — hook delegates on device if exposed
}

Device state flow: None → Starting → BIOS → Running — see C++ Reference.


GoalClassKey overrides
New appUOperatingSystemBaseProgramOnValidate, OnStart, OnClose, OnOpenFile
Saved prefsUOperatingSystemProgramSettingsSaveGame UPROPERTYs
Runtime stateUOperatingSystemProgramDataProgram-owned data
Program UIUOperatingSystemProgramWidgetNativeConstruct
CLI commandUOperatingSystemTerminalCommandOnProcessCommand, FinishCommand
File extensionUOperatingSystemFileOnOpen, Extension, TargetProgramClass
Settings panelUOperatingSystemSettingModuleOnApplySetting
World eventsUGlobalMessageSubsystemBroadcastMessage, ListenToMessage
In-OS eventsUOperatingSystemDeviceMessengerBroadcast, BeginListening