diff --git a/Source/GameBaseFramework/Private/Engine/GBFLocalPlayer.cpp b/Source/GameBaseFramework/Private/Engine/GBFLocalPlayer.cpp index f44baf6b..aefdf1f7 100644 --- a/Source/GameBaseFramework/Private/Engine/GBFLocalPlayer.cpp +++ b/Source/GameBaseFramework/Private/Engine/GBFLocalPlayer.cpp @@ -47,7 +47,7 @@ UGBFGameUserSettings * UGBFLocalPlayer::GetLocalSettings() const return UGBFGameUserSettings::Get(); } -UGBFSaveGame * UGBFLocalPlayer::GetSharedSettings() const +UGBFSettingsShared * UGBFLocalPlayer::GetSharedSettings() const { if ( SharedSettings == nullptr ) { @@ -56,12 +56,12 @@ UGBFSaveGame * UGBFLocalPlayer::GetSharedSettings() const if ( PLATFORM_DESKTOP ) { - SharedSettings = UGBFSaveGame::LoadOrCreateSettings( this ); + SharedSettings = UGBFSettingsShared::LoadOrCreateSettings( this ); } else { // We need to wait for user login to get the real settings so return temp ones - SharedSettings = UGBFSaveGame::CreateTemporarySettings( this ); + SharedSettings = UGBFSettingsShared::CreateTemporarySettings( this ); } } @@ -77,10 +77,10 @@ void UGBFLocalPlayer::LoadSharedSettingsFromDisk( bool force_load ) return; } - ensure( UGBFSaveGame::AsyncLoadOrCreateSettings( this, GetSaveGameClass(), UGBFSaveGame::FGBFOnSettingsLoadedEvent::CreateUObject( this, &UGBFLocalPlayer::OnSharedSettingsLoaded ) ) ); + ensure( UGBFSettingsShared::AsyncLoadOrCreateSettings( this, GetSaveGameClass(), UGBFSettingsShared::FGBFOnSettingsLoadedEvent::CreateUObject( this, &UGBFLocalPlayer::OnSharedSettingsLoaded ) ) ); } -void UGBFLocalPlayer::OnSharedSettingsLoaded( UGBFSaveGame * loaded_or_created_settings ) +void UGBFLocalPlayer::OnSharedSettingsLoaded( UGBFSettingsShared * loaded_or_created_settings ) { // The settings are applied before it gets here if ( ensure( loaded_or_created_settings ) ) @@ -99,9 +99,9 @@ void UGBFLocalPlayer::OnAudioOutputDeviceChanged( const FString & audio_output_d UAudioMixerBlueprintLibrary::SwapAudioOutputDevice( GetWorld(), audio_output_device_id, devices_swapped_callback ); } -TSubclassOf< UGBFSaveGame > UGBFLocalPlayer::GetSaveGameClass() const +TSubclassOf< UGBFSettingsShared > UGBFLocalPlayer::GetSaveGameClass() const { - return UGBFSaveGame::StaticClass(); + return UGBFSettingsShared::StaticClass(); } void UGBFLocalPlayer::OnCompletedAudioDeviceSwap( const FSwapAudioOutputResult & swap_result ) diff --git a/Source/GameBaseFramework/Private/GameBaseFrameworkPCH.h b/Source/GameBaseFramework/Private/GameBaseFrameworkPCH.h index c4dedd8a..c4afcc03 100644 --- a/Source/GameBaseFramework/Private/GameBaseFrameworkPCH.h +++ b/Source/GameBaseFramework/Private/GameBaseFrameworkPCH.h @@ -2,4 +2,4 @@ #include "Engine/GBFGameInstance.h" #include "GameBaseFrameworkDeveloperSettings.h" -#include "GameFramework/GBFSaveGame.h" \ No newline at end of file +#include "GameFramework/GBFSettingsShared.h" diff --git a/Source/GameBaseFramework/Private/GameFramework/GBFSaveGame.cpp b/Source/GameBaseFramework/Private/GameFramework/GBFSettingsShared.cpp similarity index 76% rename from Source/GameBaseFramework/Private/GameFramework/GBFSaveGame.cpp rename to Source/GameBaseFramework/Private/GameFramework/GBFSettingsShared.cpp index 4786c431..665b1712 100644 --- a/Source/GameBaseFramework/Private/GameFramework/GBFSaveGame.cpp +++ b/Source/GameBaseFramework/Private/GameFramework/GBFSettingsShared.cpp @@ -1,259 +1,259 @@ -#include "GameFramework/GBFSaveGame.h" - -#include "Engine/GBFLocalPlayer.h" - -#include -#include -#include -#include -#include -#include -#include - -namespace -{ - const FString SharedSettingsSlotName = TEXT( "SharedGameSettings" ); -} - -namespace GBFSettingsSharedCVars -{ - static float DefaultGamepadLeftStickInnerDeadZone = 0.25f; - static FAutoConsoleVariableRef CVarGamepadLeftStickInnerDeadZone( - TEXT( "gpad.DefaultLeftStickInnerDeadZone" ), - DefaultGamepadLeftStickInnerDeadZone, - TEXT( "Gamepad left stick inner deadzone" ) ); - - static float DefaultGamepadRightStickInnerDeadZone = 0.25f; - static FAutoConsoleVariableRef CVarGamepadRightStickInnerDeadZone( - TEXT( "gpad.DefaultRightStickInnerDeadZone" ), - DefaultGamepadRightStickInnerDeadZone, - TEXT( "Gamepad right stick inner deadzone" ) ); -} - -UGBFSaveGame::UGBFSaveGame() -{ - FInternationalization::Get().OnCultureChanged().AddUObject( this, &ThisClass::OnCultureChanged ); - - GamepadMoveStickDeadZone = GBFSettingsSharedCVars::DefaultGamepadLeftStickInnerDeadZone; - GamepadLookStickDeadZone = GBFSettingsSharedCVars::DefaultGamepadRightStickInnerDeadZone; -} - -int32 UGBFSaveGame::GetLatestDataVersion() const -{ - // 0 = before subclassing ULocalPlayerSaveGame - // 1 = first proper version - return 1; -} - -UGBFSaveGame * UGBFSaveGame::CreateTemporarySettings( const UGBFLocalPlayer * local_player ) -{ - // This is not loaded from disk but should be set up to save - auto * shared_settings = Cast< UGBFSaveGame >( CreateNewSaveGameForLocalPlayer( StaticClass(), local_player, SharedSettingsSlotName ) ); - shared_settings->ApplySettings(); - - return shared_settings; -} - -UGBFSaveGame * UGBFSaveGame::LoadOrCreateSettings( const UGBFLocalPlayer * local_player ) -{ - // This will stall the main thread while it loads - auto * shared_settings = Cast< UGBFSaveGame >( LoadOrCreateSaveGameForLocalPlayer( StaticClass(), local_player, SharedSettingsSlotName ) ); - shared_settings->ApplySettings(); - - return shared_settings; -} - -bool UGBFSaveGame::AsyncLoadOrCreateSettings( const UGBFLocalPlayer * local_player, const TSubclassOf< UGBFSaveGame > & save_game_class, FGBFOnSettingsLoadedEvent delegate ) -{ - const auto lambda = FOnLocalPlayerSaveGameLoadedNative::CreateLambda( [ delegate ]( ULocalPlayerSaveGame * loaded_save ) { - auto * loaded_settings = CastChecked< UGBFSaveGame >( loaded_save ); - loaded_settings->ApplySettings(); - - delegate.ExecuteIfBound( loaded_settings ); - } ); - - return AsyncLoadOrCreateSaveGameForLocalPlayer( save_game_class, local_player, SharedSettingsSlotName, lambda ); -} - -void UGBFSaveGame::SaveSettings() -{ - // Schedule an async save because it's okay if it fails - AsyncSaveGameToSlotForLocalPlayer(); - - // TODO_BH: Move this to the serialize function instead with a bumped version number - if ( const auto * system = ULocalPlayer::GetSubsystem< UEnhancedInputLocalPlayerSubsystem >( OwningPlayer ) ) - { - if ( auto * input_settings = system->GetUserSettings() ) - { - input_settings->AsyncSaveSettings(); - } - } -} - -void UGBFSaveGame::ApplySettings() -{ - // :TODO: Subtitles - // ApplySubtitleOptions(); - ApplyBackgroundAudioSettings(); - ApplyCultureSettings(); - - if ( const auto * system = ULocalPlayer::GetSubsystem< UEnhancedInputLocalPlayerSubsystem >( OwningPlayer ) ) - { - if ( auto * input_settings = system->GetUserSettings() ) - { - input_settings->ApplySettings(); - } - } -} - -void UGBFSaveGame::SetColorBlindStrength( int32 InColorBlindStrength ) -{ - InColorBlindStrength = FMath::Clamp( InColorBlindStrength, 0, 10 ); - if ( ColorBlindStrength != InColorBlindStrength ) - { - ColorBlindStrength = InColorBlindStrength; - FSlateApplication::Get().GetRenderer()->SetColorVisionDeficiencyType( - ( EColorVisionDeficiency ) ( int32 ) ColorBlindMode, - ( int32 ) ColorBlindStrength, - true, - false ); - } -} - -int32 UGBFSaveGame::GetColorBlindStrength() const -{ - return ColorBlindStrength; -} - -void UGBFSaveGame::SetColorBlindMode( EGBFColorBlindMode InMode ) -{ - if ( ColorBlindMode != InMode ) - { - ColorBlindMode = InMode; - FSlateApplication::Get().GetRenderer()->SetColorVisionDeficiencyType( - ( EColorVisionDeficiency ) ( int32 ) ColorBlindMode, - ( int32 ) ColorBlindStrength, - true, - false ); - } -} - -EGBFColorBlindMode UGBFSaveGame::GetColorBlindMode() const -{ - return ColorBlindMode; -} - -// void UGBFSaveGame::ApplySubtitleOptions() -//{ -// if ( USubtitleDisplaySubsystem * SubtitleSystem = USubtitleDisplaySubsystem::Get( OwningPlayer ) ) -// { -// FSubtitleFormat SubtitleFormat; -// SubtitleFormat.SubtitleTextSize = SubtitleTextSize; -// SubtitleFormat.SubtitleTextColor = SubtitleTextColor; -// SubtitleFormat.SubtitleTextBorder = SubtitleTextBorder; -// SubtitleFormat.SubtitleBackgroundOpacity = SubtitleBackgroundOpacity; -// -// SubtitleSystem->SetSubtitleDisplayOptions( SubtitleFormat ); -// } -// } - -////////////////////////////////////////////////////////////////////// - -void UGBFSaveGame::SetAllowAudioInBackgroundSetting( EGBFAllowBackgroundAudioSetting NewValue ) -{ - if ( ChangeValueAndDirty( AllowAudioInBackground, NewValue ) ) - { - ApplyBackgroundAudioSettings(); - } -} - -void UGBFSaveGame::ApplyBackgroundAudioSettings() -{ - if ( OwningPlayer && OwningPlayer->IsPrimaryPlayer() ) - { - FApp::SetUnfocusedVolumeMultiplier( ( AllowAudioInBackground != EGBFAllowBackgroundAudioSetting::Off ) ? 1.0f : 0.0f ); - } -} - -////////////////////////////////////////////////////////////////////// - -void UGBFSaveGame::ApplyCultureSettings() -{ - if ( bResetToDefaultCulture ) - { - const FCulturePtr SystemDefaultCulture = FInternationalization::Get().GetDefaultCulture(); - check( SystemDefaultCulture.IsValid() ); - - const FString CultureToApply = SystemDefaultCulture->GetName(); - if ( FInternationalization::Get().SetCurrentCulture( CultureToApply ) ) - { - // Clear this string - GConfig->RemoveKey( TEXT( "Internationalization" ), TEXT( "Culture" ), GGameUserSettingsIni ); - GConfig->Flush( false, GGameUserSettingsIni ); - } - bResetToDefaultCulture = false; - } - else if ( !PendingCulture.IsEmpty() ) - { - // SetCurrentCulture may trigger PendingCulture to be cleared (if a culture change is broadcast) so we take a copy of it to work with - const FString CultureToApply = PendingCulture; - if ( FInternationalization::Get().SetCurrentCulture( CultureToApply ) ) - { - // Note: This is intentionally saved to the users config - // We need to localize text before the player logs in and very early in the loading screen - GConfig->SetString( TEXT( "Internationalization" ), TEXT( "Culture" ), *CultureToApply, GGameUserSettingsIni ); - GConfig->Flush( false, GGameUserSettingsIni ); - } - ClearPendingCulture(); - } -} - -void UGBFSaveGame::ResetCultureToCurrentSettings() -{ - ClearPendingCulture(); - bResetToDefaultCulture = false; -} - -const FString & UGBFSaveGame::GetPendingCulture() const -{ - return PendingCulture; -} - -void UGBFSaveGame::SetPendingCulture( const FString & NewCulture ) -{ - PendingCulture = NewCulture; - bResetToDefaultCulture = false; - bIsDirty = true; -} - -void UGBFSaveGame::OnCultureChanged() -{ - ClearPendingCulture(); - bResetToDefaultCulture = false; -} - -void UGBFSaveGame::ClearPendingCulture() -{ - PendingCulture.Reset(); -} - -bool UGBFSaveGame::IsUsingDefaultCulture() const -{ - FString Culture; - GConfig->GetString( TEXT( "Internationalization" ), TEXT( "Culture" ), Culture, GGameUserSettingsIni ); - - return Culture.IsEmpty(); -} - -void UGBFSaveGame::ResetToDefaultCulture() -{ - ClearPendingCulture(); - bResetToDefaultCulture = true; - bIsDirty = true; -} - -////////////////////////////////////////////////////////////////////// - -void UGBFSaveGame::ApplyInputSensitivity() -{ +#include "GameFramework/GBFSettingsShared.h" + +#include "Engine/GBFLocalPlayer.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + const FString SharedSettingsSlotName = TEXT( "SharedGameSettings" ); +} + +namespace GBFSettingsSharedCVars +{ + static float DefaultGamepadLeftStickInnerDeadZone = 0.25f; + static FAutoConsoleVariableRef CVarGamepadLeftStickInnerDeadZone( + TEXT( "gpad.DefaultLeftStickInnerDeadZone" ), + DefaultGamepadLeftStickInnerDeadZone, + TEXT( "Gamepad left stick inner deadzone" ) ); + + static float DefaultGamepadRightStickInnerDeadZone = 0.25f; + static FAutoConsoleVariableRef CVarGamepadRightStickInnerDeadZone( + TEXT( "gpad.DefaultRightStickInnerDeadZone" ), + DefaultGamepadRightStickInnerDeadZone, + TEXT( "Gamepad right stick inner deadzone" ) ); +} + +UGBFSettingsShared::UGBFSettingsShared() +{ + FInternationalization::Get().OnCultureChanged().AddUObject( this, &ThisClass::OnCultureChanged ); + + GamepadMoveStickDeadZone = GBFSettingsSharedCVars::DefaultGamepadLeftStickInnerDeadZone; + GamepadLookStickDeadZone = GBFSettingsSharedCVars::DefaultGamepadRightStickInnerDeadZone; +} + +int32 UGBFSettingsShared::GetLatestDataVersion() const +{ + // 0 = before subclassing ULocalPlayerSaveGame + // 1 = first proper version + return 1; +} + +UGBFSettingsShared * UGBFSettingsShared::CreateTemporarySettings( const UGBFLocalPlayer * local_player ) +{ + // This is not loaded from disk but should be set up to save + auto * shared_settings = Cast< UGBFSettingsShared >( CreateNewSaveGameForLocalPlayer( StaticClass(), local_player, SharedSettingsSlotName ) ); + shared_settings->ApplySettings(); + + return shared_settings; +} + +UGBFSettingsShared * UGBFSettingsShared::LoadOrCreateSettings( const UGBFLocalPlayer * local_player ) +{ + // This will stall the main thread while it loads + auto * shared_settings = Cast< UGBFSettingsShared >( LoadOrCreateSaveGameForLocalPlayer( StaticClass(), local_player, SharedSettingsSlotName ) ); + shared_settings->ApplySettings(); + + return shared_settings; +} + +bool UGBFSettingsShared::AsyncLoadOrCreateSettings( const UGBFLocalPlayer * local_player, const TSubclassOf< UGBFSettingsShared > & save_game_class, FGBFOnSettingsLoadedEvent delegate ) +{ + const auto lambda = FOnLocalPlayerSaveGameLoadedNative::CreateLambda( [ delegate ]( ULocalPlayerSaveGame * loaded_save ) { + auto * loaded_settings = CastChecked< UGBFSettingsShared >( loaded_save ); + loaded_settings->ApplySettings(); + + delegate.ExecuteIfBound( loaded_settings ); + } ); + + return AsyncLoadOrCreateSaveGameForLocalPlayer( save_game_class, local_player, SharedSettingsSlotName, lambda ); +} + +void UGBFSettingsShared::SaveSettings() +{ + // Schedule an async save because it's okay if it fails + AsyncSaveGameToSlotForLocalPlayer(); + + // TODO_BH: Move this to the serialize function instead with a bumped version number + if ( const auto * system = ULocalPlayer::GetSubsystem< UEnhancedInputLocalPlayerSubsystem >( OwningPlayer ) ) + { + if ( auto * input_settings = system->GetUserSettings() ) + { + input_settings->AsyncSaveSettings(); + } + } +} + +void UGBFSettingsShared::ApplySettings() +{ + // :TODO: Subtitles + // ApplySubtitleOptions(); + ApplyBackgroundAudioSettings(); + ApplyCultureSettings(); + + if ( const auto * system = ULocalPlayer::GetSubsystem< UEnhancedInputLocalPlayerSubsystem >( OwningPlayer ) ) + { + if ( auto * input_settings = system->GetUserSettings() ) + { + input_settings->ApplySettings(); + } + } +} + +void UGBFSettingsShared::SetColorBlindStrength( int32 InColorBlindStrength ) +{ + InColorBlindStrength = FMath::Clamp( InColorBlindStrength, 0, 10 ); + if ( ColorBlindStrength != InColorBlindStrength ) + { + ColorBlindStrength = InColorBlindStrength; + FSlateApplication::Get().GetRenderer()->SetColorVisionDeficiencyType( + ( EColorVisionDeficiency ) ( int32 ) ColorBlindMode, + ( int32 ) ColorBlindStrength, + true, + false ); + } +} + +int32 UGBFSettingsShared::GetColorBlindStrength() const +{ + return ColorBlindStrength; +} + +void UGBFSettingsShared::SetColorBlindMode( EGBFColorBlindMode InMode ) +{ + if ( ColorBlindMode != InMode ) + { + ColorBlindMode = InMode; + FSlateApplication::Get().GetRenderer()->SetColorVisionDeficiencyType( + ( EColorVisionDeficiency ) ( int32 ) ColorBlindMode, + ( int32 ) ColorBlindStrength, + true, + false ); + } +} + +EGBFColorBlindMode UGBFSettingsShared::GetColorBlindMode() const +{ + return ColorBlindMode; +} + +// void UGBFSettingsShared::ApplySubtitleOptions() +//{ +// if ( USubtitleDisplaySubsystem * SubtitleSystem = USubtitleDisplaySubsystem::Get( OwningPlayer ) ) +// { +// FSubtitleFormat SubtitleFormat; +// SubtitleFormat.SubtitleTextSize = SubtitleTextSize; +// SubtitleFormat.SubtitleTextColor = SubtitleTextColor; +// SubtitleFormat.SubtitleTextBorder = SubtitleTextBorder; +// SubtitleFormat.SubtitleBackgroundOpacity = SubtitleBackgroundOpacity; +// +// SubtitleSystem->SetSubtitleDisplayOptions( SubtitleFormat ); +// } +// } + +////////////////////////////////////////////////////////////////////// + +void UGBFSettingsShared::SetAllowAudioInBackgroundSetting( EGBFAllowBackgroundAudioSetting NewValue ) +{ + if ( ChangeValueAndDirty( AllowAudioInBackground, NewValue ) ) + { + ApplyBackgroundAudioSettings(); + } +} + +void UGBFSettingsShared::ApplyBackgroundAudioSettings() +{ + if ( OwningPlayer && OwningPlayer->IsPrimaryPlayer() ) + { + FApp::SetUnfocusedVolumeMultiplier( ( AllowAudioInBackground != EGBFAllowBackgroundAudioSetting::Off ) ? 1.0f : 0.0f ); + } +} + +////////////////////////////////////////////////////////////////////// + +void UGBFSettingsShared::ApplyCultureSettings() +{ + if ( bResetToDefaultCulture ) + { + const FCulturePtr SystemDefaultCulture = FInternationalization::Get().GetDefaultCulture(); + check( SystemDefaultCulture.IsValid() ); + + const FString CultureToApply = SystemDefaultCulture->GetName(); + if ( FInternationalization::Get().SetCurrentCulture( CultureToApply ) ) + { + // Clear this string + GConfig->RemoveKey( TEXT( "Internationalization" ), TEXT( "Culture" ), GGameUserSettingsIni ); + GConfig->Flush( false, GGameUserSettingsIni ); + } + bResetToDefaultCulture = false; + } + else if ( !PendingCulture.IsEmpty() ) + { + // SetCurrentCulture may trigger PendingCulture to be cleared (if a culture change is broadcast) so we take a copy of it to work with + const FString CultureToApply = PendingCulture; + if ( FInternationalization::Get().SetCurrentCulture( CultureToApply ) ) + { + // Note: This is intentionally saved to the users config + // We need to localize text before the player logs in and very early in the loading screen + GConfig->SetString( TEXT( "Internationalization" ), TEXT( "Culture" ), *CultureToApply, GGameUserSettingsIni ); + GConfig->Flush( false, GGameUserSettingsIni ); + } + ClearPendingCulture(); + } +} + +void UGBFSettingsShared::ResetCultureToCurrentSettings() +{ + ClearPendingCulture(); + bResetToDefaultCulture = false; +} + +const FString & UGBFSettingsShared::GetPendingCulture() const +{ + return PendingCulture; +} + +void UGBFSettingsShared::SetPendingCulture( const FString & NewCulture ) +{ + PendingCulture = NewCulture; + bResetToDefaultCulture = false; + bIsDirty = true; +} + +void UGBFSettingsShared::OnCultureChanged() +{ + ClearPendingCulture(); + bResetToDefaultCulture = false; +} + +void UGBFSettingsShared::ClearPendingCulture() +{ + PendingCulture.Reset(); +} + +bool UGBFSettingsShared::IsUsingDefaultCulture() const +{ + FString Culture; + GConfig->GetString( TEXT( "Internationalization" ), TEXT( "Culture" ), Culture, GGameUserSettingsIni ); + + return Culture.IsEmpty(); +} + +void UGBFSettingsShared::ResetToDefaultCulture() +{ + ClearPendingCulture(); + bResetToDefaultCulture = true; + bIsDirty = true; +} + +////////////////////////////////////////////////////////////////////// + +void UGBFSettingsShared::ApplyInputSensitivity() +{ } \ No newline at end of file diff --git a/Source/GameBaseFramework/Private/Input/Modifiers/GBFInputModifier_SettingsBased_Scalar3.cpp b/Source/GameBaseFramework/Private/Input/Modifiers/GBFInputModifier_SettingsBased_Scalar3.cpp index 34c9a6d9..eed6b225 100644 --- a/Source/GameBaseFramework/Private/Input/Modifiers/GBFInputModifier_SettingsBased_Scalar3.cpp +++ b/Source/GameBaseFramework/Private/Input/Modifiers/GBFInputModifier_SettingsBased_Scalar3.cpp @@ -8,7 +8,7 @@ FInputActionValue UGBFInputModifier_SettingsBased_Scalar3::ModifyRaw_Implementat { if ( const auto * local_player = GBFInputModifiersHelpers::GetLocalPlayer( player_input ) ) { - const auto * settings_class = UGBFSaveGame::StaticClass(); + const auto * settings_class = UGBFSettingsShared::StaticClass(); auto * shared_settings = local_player->GetSharedSettings(); const auto has_cached_property = PropertyCache.Num() == 3; diff --git a/Source/GameBaseFramework/Private/Settings/GBFGameSettingRegistry_Audio.cpp b/Source/GameBaseFramework/Private/Settings/GBFGameSettingRegistry_Audio.cpp index 5bffefa2..f737b447 100644 --- a/Source/GameBaseFramework/Private/Settings/GBFGameSettingRegistry_Audio.cpp +++ b/Source/GameBaseFramework/Private/Settings/GBFGameSettingRegistry_Audio.cpp @@ -154,7 +154,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeAudioSettings( UGBFL // setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetSubtitlesEnabled ) ); // setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetSubtitlesEnabled ) ); - // setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetSubtitlesEnabled() ); + // setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetSubtitlesEnabled() ); // subtitle_collection->AddSetting( setting ); // } @@ -167,7 +167,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeAudioSettings( UGBFL // Setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetSubtitlesTextSize ) ); // Setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetSubtitlesTextSize ) ); - // Setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetSubtitlesTextSize() ); + // Setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetSubtitlesTextSize() ); // Setting->AddEnumOption( ESubtitleDisplayTextSize::ExtraSmall, LOCTEXT( "ESubtitleTextSize_ExtraSmall", "Extra Small" ) ); // Setting->AddEnumOption( ESubtitleDisplayTextSize::Small, LOCTEXT( "ESubtitleTextSize_Small", "Small" ) ); // Setting->AddEnumOption( ESubtitleDisplayTextSize::Medium, LOCTEXT( "ESubtitleTextSize_Medium", "Medium" ) ); @@ -185,7 +185,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeAudioSettings( UGBFL // Setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetSubtitlesTextColor ) ); // Setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetSubtitlesTextColor ) ); - // Setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetSubtitlesTextColor() ); + // Setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetSubtitlesTextColor() ); // Setting->AddEnumOption( ESubtitleDisplayTextColor::White, LOCTEXT( "ESubtitleTextColor_White", "White" ) ); // Setting->AddEnumOption( ESubtitleDisplayTextColor::Yellow, LOCTEXT( "ESubtitleTextColor_Yellow", "Yellow" ) ); @@ -200,7 +200,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeAudioSettings( UGBFL // Setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetSubtitlesTextBorder ) ); // Setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetSubtitlesTextBorder ) ); - // Setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetSubtitlesTextBorder() ); + // Setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetSubtitlesTextBorder() ); // Setting->AddEnumOption( ESubtitleDisplayTextBorder::None, LOCTEXT( "ESubtitleTextBorder_None", "None" ) ); // Setting->AddEnumOption( ESubtitleDisplayTextBorder::Outline, LOCTEXT( "ESubtitleTextBorder_Outline", "Outline" ) ); // Setting->AddEnumOption( ESubtitleDisplayTextBorder::DropShadow, LOCTEXT( "ESubtitleTextBorder_DropShadow", "Drop Shadow" ) ); @@ -216,7 +216,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeAudioSettings( UGBFL // Setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetSubtitlesBackgroundOpacity ) ); // Setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetSubtitlesBackgroundOpacity ) ); - // Setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetSubtitlesBackgroundOpacity() ); + // Setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetSubtitlesBackgroundOpacity() ); // Setting->AddEnumOption( ESubtitleDisplayBackgroundOpacity::Clear, LOCTEXT( "ESubtitleBackgroundOpacity_Clear", "Clear" ) ); // Setting->AddEnumOption( ESubtitleDisplayBackgroundOpacity::Low, LOCTEXT( "ESubtitleBackgroundOpacity_Low", "Low" ) ); // Setting->AddEnumOption( ESubtitleDisplayBackgroundOpacity::Medium, LOCTEXT( "ESubtitleBackgroundOpacity_Medium", "Medium" ) ); @@ -253,7 +253,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeAudioSettings( UGBFL setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetAllowAudioInBackgroundSetting ) ); setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetAllowAudioInBackgroundSetting ) ); - setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetAllowAudioInBackgroundSetting() ); + setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetAllowAudioInBackgroundSetting() ); setting->AddEnumOption( EGBFAllowBackgroundAudioSetting::Off, LOCTEXT( "EGBFAllowBackgroundAudioSetting_Off", "Off" ) ); setting->AddEnumOption( EGBFAllowBackgroundAudioSetting::AllSounds, LOCTEXT( "EGBFAllowBackgroundAudioSetting_AllSounds", "All Sounds" ) ); diff --git a/Source/GameBaseFramework/Private/Settings/GBFGameSettingRegistry_Gamepad.cpp b/Source/GameBaseFramework/Private/Settings/GBFGameSettingRegistry_Gamepad.cpp index 1b3702ea..ae6a3e95 100644 --- a/Source/GameBaseFramework/Private/Settings/GBFGameSettingRegistry_Gamepad.cpp +++ b/Source/GameBaseFramework/Private/Settings/GBFGameSettingRegistry_Gamepad.cpp @@ -80,7 +80,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeGamepadSettings( UGB setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetForceFeedbackEnabled ) ); setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetForceFeedbackEnabled ) ); - setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetForceFeedbackEnabled() ); + setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetForceFeedbackEnabled() ); hardware->AddSetting( setting ); } @@ -93,7 +93,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeGamepadSettings( UGB setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetInvertVerticalAxis ) ); setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetInvertVerticalAxis ) ); - setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetInvertVerticalAxis() ); + setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetInvertVerticalAxis() ); hardware->AddSetting( setting ); } @@ -106,7 +106,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeGamepadSettings( UGB setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetInvertHorizontalAxis ) ); setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetInvertHorizontalAxis ) ); - setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetInvertHorizontalAxis() ); + setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetInvertHorizontalAxis() ); hardware->AddSetting( setting ); } @@ -130,7 +130,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeGamepadSettings( UGB setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetGamepadMoveStickDeadZone ) ); setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetGamepadMoveStickDeadZone ) ); - setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetGamepadMoveStickDeadZone() ); + setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetGamepadMoveStickDeadZone() ); setting->SetDisplayFormat( UGameSettingValueScalarDynamic::ZeroToOnePercent ); setting->SetMinimumLimit( 0.05 ); setting->SetMaximumLimit( 0.95 ); @@ -146,7 +146,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeGamepadSettings( UGB setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetGamepadLookStickDeadZone ) ); setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetGamepadLookStickDeadZone ) ); - setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetGamepadLookStickDeadZone() ); + setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetGamepadLookStickDeadZone() ); setting->SetDisplayFormat( UGameSettingValueScalarDynamic::ZeroToOnePercent ); setting->SetMinimumLimit( 0.05 ); setting->SetMaximumLimit( 0.95 ); diff --git a/Source/GameBaseFramework/Private/Settings/GBFGameSettingRegistry_MouseAndKeyboard.cpp b/Source/GameBaseFramework/Private/Settings/GBFGameSettingRegistry_MouseAndKeyboard.cpp index 5b7b41cb..aaa66890 100644 --- a/Source/GameBaseFramework/Private/Settings/GBFGameSettingRegistry_MouseAndKeyboard.cpp +++ b/Source/GameBaseFramework/Private/Settings/GBFGameSettingRegistry_MouseAndKeyboard.cpp @@ -45,7 +45,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeMouseAndKeyboardSett setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetMouseSensitivityX ) ); setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetMouseSensitivityX ) ); - setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetMouseSensitivityX() ); + setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetMouseSensitivityX() ); setting->SetDisplayFormat( UGameSettingValueScalarDynamic::RawTwoDecimals ); setting->SetSourceRangeAndStep( TRange< double >( 0, 10 ), 0.01 ); setting->SetMinimumLimit( 0.01 ); @@ -63,7 +63,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeMouseAndKeyboardSett setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetMouseSensitivityY ) ); setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetMouseSensitivityY ) ); - setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetMouseSensitivityY() ); + setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetMouseSensitivityY() ); setting->SetDisplayFormat( UGameSettingValueScalarDynamic::RawTwoDecimals ); setting->SetSourceRangeAndStep( TRange< double >( 0, 10 ), 0.01 ); setting->SetMinimumLimit( 0.01 ); @@ -81,7 +81,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeMouseAndKeyboardSett setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetTargetingMultiplier ) ); setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetTargetingMultiplier ) ); - setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetTargetingMultiplier() ); + setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetTargetingMultiplier() ); setting->SetDisplayFormat( UGameSettingValueScalarDynamic::RawTwoDecimals ); setting->SetSourceRangeAndStep( TRange< double >( 0, 10 ), 0.01 ); setting->SetMinimumLimit( 0.01 ); @@ -99,7 +99,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeMouseAndKeyboardSett setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetInvertVerticalAxis ) ); setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetInvertVerticalAxis ) ); - setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetInvertVerticalAxis() ); + setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetInvertVerticalAxis() ); setting->AddEditCondition( when_platform_supports_mouse_and_keyboard ); @@ -114,7 +114,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeMouseAndKeyboardSett setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetInvertHorizontalAxis ) ); setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetInvertHorizontalAxis ) ); - setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetInvertHorizontalAxis() ); + setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetInvertHorizontalAxis() ); setting->AddEditCondition( when_platform_supports_mouse_and_keyboard ); diff --git a/Source/GameBaseFramework/Private/Settings/GBFGameSettingRegistry_Video.cpp b/Source/GameBaseFramework/Private/Settings/GBFGameSettingRegistry_Video.cpp index 3ee9a873..1c4f91e8 100644 --- a/Source/GameBaseFramework/Private/Settings/GBFGameSettingRegistry_Video.cpp +++ b/Source/GameBaseFramework/Private/Settings/GBFGameSettingRegistry_Video.cpp @@ -161,7 +161,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeVideoSettings( UGBFL setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetColorBlindMode ) ); setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetColorBlindMode ) ); - setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetColorBlindMode() ); + setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetColorBlindMode() ); setting->AddEnumOption( EGBFColorBlindMode::Off, LOCTEXT( "ColorBlindRotatorSettingOff", "Off" ) ); setting->AddEnumOption( EGBFColorBlindMode::Deuteranope, LOCTEXT( "ColorBlindRotatorSettingDeuteranope", "Deuteranope" ) ); setting->AddEnumOption( EGBFColorBlindMode::Protanope, LOCTEXT( "ColorBlindRotatorSettingProtanope", "Protanope" ) ); @@ -180,7 +180,7 @@ UGameSettingCollection * UGBFGameSettingRegistry::InitializeVideoSettings( UGBFL setting->SetDynamicGetter( GET_SHARED_SETTINGS_FUNCTION_PATH( GetColorBlindStrength ) ); setting->SetDynamicSetter( GET_SHARED_SETTINGS_FUNCTION_PATH( SetColorBlindStrength ) ); - setting->SetDefaultValue( GetDefault< UGBFSaveGame >()->GetColorBlindStrength() ); + setting->SetDefaultValue( GetDefault< UGBFSettingsShared >()->GetColorBlindStrength() ); for ( auto index = 0; index <= 10; index++ ) { setting->AddOption( index, FText::AsNumber( index ) ); diff --git a/Source/GameBaseFramework/Public/Engine/GBFLocalPlayer.h b/Source/GameBaseFramework/Public/Engine/GBFLocalPlayer.h index 68a8f07a..b928e107 100644 --- a/Source/GameBaseFramework/Public/Engine/GBFLocalPlayer.h +++ b/Source/GameBaseFramework/Public/Engine/GBFLocalPlayer.h @@ -8,7 +8,7 @@ struct FSwapAudioOutputResult; class UGBFGameUserSettings; -class UGBFSaveGame; +class UGBFSettingsShared; UCLASS( BlueprintType ) class GAMEBASEFRAMEWORK_API UGBFLocalPlayer : public UCommonLocalPlayer @@ -30,21 +30,21 @@ class GAMEBASEFRAMEWORK_API UGBFLocalPlayer : public UCommonLocalPlayer /** Gets the shared setting for this player, this is read using the save game system so may not be correct until after user login */ UFUNCTION( BlueprintPure ) - virtual UGBFSaveGame * GetSharedSettings() const; + virtual UGBFSettingsShared * GetSharedSettings() const; /** Starts an async request to load the shared settings, this will call OnSharedSettingsLoaded after loading or creating new ones */ void LoadSharedSettingsFromDisk( bool force_load = false ); protected: - void OnSharedSettingsLoaded( UGBFSaveGame * loaded_or_created_settings ); + void OnSharedSettingsLoaded( UGBFSettingsShared * loaded_or_created_settings ); void OnAudioOutputDeviceChanged( const FString & audio_output_device_id ); - virtual TSubclassOf< UGBFSaveGame > GetSaveGameClass() const; + virtual TSubclassOf< UGBFSettingsShared > GetSaveGameClass() const; UFUNCTION() void OnCompletedAudioDeviceSwap( const FSwapAudioOutputResult & swap_result ); UPROPERTY( Transient ) - mutable TObjectPtr< UGBFSaveGame > SharedSettings; + mutable TObjectPtr< UGBFSettingsShared > SharedSettings; FUniqueNetIdRepl NetIdForSharedSettings; diff --git a/Source/GameBaseFramework/Public/GameFramework/GBFSaveGame.h b/Source/GameBaseFramework/Public/GameFramework/GBFSettingsShared.h similarity index 92% rename from Source/GameBaseFramework/Public/GameFramework/GBFSaveGame.h rename to Source/GameBaseFramework/Public/GameFramework/GBFSettingsShared.h index d89acc6a..51e81010 100644 --- a/Source/GameBaseFramework/Public/GameFramework/GBFSaveGame.h +++ b/Source/GameBaseFramework/Public/GameFramework/GBFSettingsShared.h @@ -1,498 +1,498 @@ -#pragma once - -#include -#include - -#include "GBFSaveGame.generated.h" - -class UGBFLocalPlayer; - -UENUM( BlueprintType ) -enum class EGBFColorBlindMode : uint8 -{ - Off, - // Deuteranope (green weak/blind) - Deuteranope, - // Protanope (red weak/blind) - Protanope, - // Tritanope(blue weak / bind) - Tritanope -}; - -UENUM( BlueprintType ) -enum class EGBFAllowBackgroundAudioSetting : uint8 -{ - Off, - AllSounds, - - Num UMETA( Hidden ), -}; - -UENUM( BlueprintType ) -enum class EGBFGamepadSensitivity : uint8 -{ - Invalid = 0 UMETA( Hidden ), - - Slow UMETA( DisplayName = "01 - Slow" ), - SlowPlus UMETA( DisplayName = "02 - Slow+" ), - SlowPlusPlus UMETA( DisplayName = "03 - Slow++" ), - Normal UMETA( DisplayName = "04 - Normal" ), - NormalPlus UMETA( DisplayName = "05 - Normal+" ), - NormalPlusPlus UMETA( DisplayName = "06 - Normal++" ), - Fast UMETA( DisplayName = "07 - Fast" ), - FastPlus UMETA( DisplayName = "08 - Fast+" ), - FastPlusPlus UMETA( DisplayName = "09 - Fast++" ), - Insane UMETA( DisplayName = "10 - Insane" ), - - MAX UMETA( Hidden ), -}; - -UCLASS( BlueprintType ) -class GAMEBASEFRAMEWORK_API UGBFSaveGame : public ULocalPlayerSaveGame -{ - GENERATED_BODY() - -public: - DECLARE_EVENT_OneParam( UGBFSaveGame, FOnSettingChangedEvent, UGBFSaveGame * Settings ); - FOnSettingChangedEvent OnSettingChanged; - - UGBFSaveGame(); - - int32 GetLatestDataVersion() const override; - - bool IsDirty() const - { - return bIsDirty; - } - void ClearDirtyFlag() - { - bIsDirty = false; - } - - /** Creates a temporary settings object, this will be replaced by one loaded from the user's save game */ - static UGBFSaveGame * CreateTemporarySettings( const UGBFLocalPlayer * local_player ); - - /** Synchronously loads a settings object, this is not valid to call before login */ - static UGBFSaveGame * LoadOrCreateSettings( const UGBFLocalPlayer * local_player ); - - DECLARE_DELEGATE_OneParam( FGBFOnSettingsLoadedEvent, UGBFSaveGame * Settings ); - - /** Starts an async load of the settings object, calls Delegate on completion */ - static bool AsyncLoadOrCreateSettings( const UGBFLocalPlayer * local_player, const TSubclassOf< UGBFSaveGame > & save_game_class, FGBFOnSettingsLoadedEvent delegate ); - - /** Saves the settings to disk */ - void SaveSettings(); - - /** Applies the current settings to the player */ - void ApplySettings(); - - //////////////////////////////////////////////////////// - // Color Blind Options - - UFUNCTION() - EGBFColorBlindMode GetColorBlindMode() const; - UFUNCTION() - void SetColorBlindMode( EGBFColorBlindMode InMode ); - - UFUNCTION() - int32 GetColorBlindStrength() const; - UFUNCTION() - void SetColorBlindStrength( int32 InColorBlindStrength ); - -private: - UPROPERTY() - EGBFColorBlindMode ColorBlindMode = EGBFColorBlindMode::Off; - - UPROPERTY() - int32 ColorBlindStrength = 10; - - //////////////////////////////////////////////////////// - // Gamepad Vibration -public: - UFUNCTION() - bool GetForceFeedbackEnabled() const - { - return bForceFeedbackEnabled; - } - - UFUNCTION() - void SetForceFeedbackEnabled( const bool NewValue ) - { - ChangeValueAndDirty( bForceFeedbackEnabled, NewValue ); - } - -private: - /** Is force feedback enabled when a controller is being used? */ - UPROPERTY() - bool bForceFeedbackEnabled = true; - - //////////////////////////////////////////////////////// - // Gamepad Deadzone -public: - /** Getter for gamepad move stick dead zone value. */ - UFUNCTION() - float GetGamepadMoveStickDeadZone() const - { - return GamepadMoveStickDeadZone; - } - - /** Setter for gamepad move stick dead zone value. */ - UFUNCTION() - void SetGamepadMoveStickDeadZone( const float NewValue ) - { - ChangeValueAndDirty( GamepadMoveStickDeadZone, NewValue ); - } - - /** Getter for gamepad look stick dead zone value. */ - UFUNCTION() - float GetGamepadLookStickDeadZone() const - { - return GamepadLookStickDeadZone; - } - - /** Setter for gamepad look stick dead zone value. */ - UFUNCTION() - void SetGamepadLookStickDeadZone( const float NewValue ) - { - ChangeValueAndDirty( GamepadLookStickDeadZone, NewValue ); - } - -private: - /** Holds the gamepad move stick dead zone value. */ - UPROPERTY() - float GamepadMoveStickDeadZone; - - /** Holds the gamepad look stick dead zone value. */ - UPROPERTY() - float GamepadLookStickDeadZone; - - //////////////////////////////////////////////////////// - // Gamepad Trigger Haptics -public: - UFUNCTION() - bool GetTriggerHapticsEnabled() const - { - return bTriggerHapticsEnabled; - } - UFUNCTION() - void SetTriggerHapticsEnabled( const bool NewValue ) - { - ChangeValueAndDirty( bTriggerHapticsEnabled, NewValue ); - } - - UFUNCTION() - bool GetTriggerPullUsesHapticThreshold() const - { - return bTriggerPullUsesHapticThreshold; - } - UFUNCTION() - void SetTriggerPullUsesHapticThreshold( const bool NewValue ) - { - ChangeValueAndDirty( bTriggerPullUsesHapticThreshold, NewValue ); - } - - UFUNCTION() - uint8 GetTriggerHapticStrength() const - { - return TriggerHapticStrength; - } - UFUNCTION() - void SetTriggerHapticStrength( const uint8 NewValue ) - { - ChangeValueAndDirty( TriggerHapticStrength, NewValue ); - } - - UFUNCTION() - uint8 GetTriggerHapticStartPosition() const - { - return TriggerHapticStartPosition; - } - UFUNCTION() - void SetTriggerHapticStartPosition( const uint8 NewValue ) - { - ChangeValueAndDirty( TriggerHapticStartPosition, NewValue ); - } - -private: - /** Are trigger haptics enabled? */ - UPROPERTY() - bool bTriggerHapticsEnabled = false; - /** Does the game use the haptic feedback as its threshold for judging button presses? */ - UPROPERTY() - bool bTriggerPullUsesHapticThreshold = true; - /** The strength of the trigger haptic effects. */ - UPROPERTY() - uint8 TriggerHapticStrength = 8; - /** The start position of the trigger haptic effects */ - UPROPERTY() - uint8 TriggerHapticStartPosition = 0; - - //////////////////////////////////////////////////////// - // Subtitles - // public: - // UFUNCTION() - // bool GetSubtitlesEnabled() const - // { - // return bEnableSubtitles; - // } - // UFUNCTION() - // void SetSubtitlesEnabled( bool Value ) - // { - // ChangeValueAndDirty( bEnableSubtitles, Value ); - // } - // - // UFUNCTION() - // ESubtitleDisplayTextSize GetSubtitlesTextSize() const - // { - // return SubtitleTextSize; - // } - // UFUNCTION() - // void SetSubtitlesTextSize( ESubtitleDisplayTextSize Value ) - // { - // ChangeValueAndDirty( SubtitleTextSize, Value ); - // ApplySubtitleOptions(); - // } - // - // UFUNCTION() - // ESubtitleDisplayTextColor GetSubtitlesTextColor() const - // { - // return SubtitleTextColor; - // } - // UFUNCTION() - // void SetSubtitlesTextColor( ESubtitleDisplayTextColor Value ) - // { - // ChangeValueAndDirty( SubtitleTextColor, Value ); - // ApplySubtitleOptions(); - // } - // - // UFUNCTION() - // ESubtitleDisplayTextBorder GetSubtitlesTextBorder() const - // { - // return SubtitleTextBorder; - // } - // UFUNCTION() - // void SetSubtitlesTextBorder( ESubtitleDisplayTextBorder Value ) - // { - // ChangeValueAndDirty( SubtitleTextBorder, Value ); - // ApplySubtitleOptions(); - // } - // - // UFUNCTION() - // ESubtitleDisplayBackgroundOpacity GetSubtitlesBackgroundOpacity() const - // { - // return SubtitleBackgroundOpacity; - // } - // UFUNCTION() - // void SetSubtitlesBackgroundOpacity( ESubtitleDisplayBackgroundOpacity Value ) - // { - // ChangeValueAndDirty( SubtitleBackgroundOpacity, Value ); - // ApplySubtitleOptions(); - // } - // - // void ApplySubtitleOptions(); - // - // private: - // UPROPERTY() - // bool bEnableSubtitles = true; - // - // UPROPERTY() - // ESubtitleDisplayTextSize SubtitleTextSize = ESubtitleDisplayTextSize::Medium; - // - // UPROPERTY() - // ESubtitleDisplayTextColor SubtitleTextColor = ESubtitleDisplayTextColor::White; - // - // UPROPERTY() - // ESubtitleDisplayTextBorder SubtitleTextBorder = ESubtitleDisplayTextBorder::None; - // - // UPROPERTY() - // ESubtitleDisplayBackgroundOpacity SubtitleBackgroundOpacity = ESubtitleDisplayBackgroundOpacity::Medium; - - //////////////////////////////////////////////////////// - // Shared audio settings -public: - UFUNCTION() - EGBFAllowBackgroundAudioSetting GetAllowAudioInBackgroundSetting() const - { - return AllowAudioInBackground; - } - UFUNCTION() - void SetAllowAudioInBackgroundSetting( EGBFAllowBackgroundAudioSetting NewValue ); - - void ApplyBackgroundAudioSettings(); - -private: - UPROPERTY() - EGBFAllowBackgroundAudioSetting AllowAudioInBackground = EGBFAllowBackgroundAudioSetting::Off; - - //////////////////////////////////////////////////////// - // Culture / language -public: - /** Gets the pending culture */ - const FString & GetPendingCulture() const; - - /** Sets the pending culture to apply */ - void SetPendingCulture( const FString & NewCulture ); - - // Called when the culture changes. - void OnCultureChanged(); - - /** Clears the pending culture to apply */ - void ClearPendingCulture(); - - bool IsUsingDefaultCulture() const; - - void ResetToDefaultCulture(); - bool ShouldResetToDefaultCulture() const - { - return bResetToDefaultCulture; - } - - void ApplyCultureSettings(); - void ResetCultureToCurrentSettings(); - -private: - /** The pending culture to apply */ - UPROPERTY( Transient ) - FString PendingCulture; - - /* If true, resets the culture to default. */ - bool bResetToDefaultCulture = false; - - //////////////////////////////////////////////////////// - // Gamepad Sensitivity -public: - UFUNCTION() - double GetMouseSensitivityX() const - { - return MouseSensitivityX; - } - UFUNCTION() - void SetMouseSensitivityX( double NewValue ) - { - ChangeValueAndDirty( MouseSensitivityX, NewValue ); - ApplyInputSensitivity(); - } - - UFUNCTION() - double GetMouseSensitivityY() const - { - return MouseSensitivityY; - } - UFUNCTION() - void SetMouseSensitivityY( double NewValue ) - { - ChangeValueAndDirty( MouseSensitivityY, NewValue ); - ApplyInputSensitivity(); - } - - UFUNCTION() - double GetTargetingMultiplier() const - { - return TargetingMultiplier; - } - UFUNCTION() - void SetTargetingMultiplier( double NewValue ) - { - ChangeValueAndDirty( TargetingMultiplier, NewValue ); - ApplyInputSensitivity(); - } - - UFUNCTION() - bool GetInvertVerticalAxis() const - { - return bInvertVerticalAxis; - } - UFUNCTION() - void SetInvertVerticalAxis( bool NewValue ) - { - ChangeValueAndDirty( bInvertVerticalAxis, NewValue ); - ApplyInputSensitivity(); - } - - UFUNCTION() - bool GetInvertHorizontalAxis() const - { - return bInvertHorizontalAxis; - } - UFUNCTION() - void SetInvertHorizontalAxis( bool NewValue ) - { - ChangeValueAndDirty( bInvertHorizontalAxis, NewValue ); - ApplyInputSensitivity(); - } - -private: - /** Holds the mouse horizontal sensitivity */ - UPROPERTY() - double MouseSensitivityX = 1.0; - - /** Holds the mouse vertical sensitivity */ - UPROPERTY() - double MouseSensitivityY = 1.0; - - /** Multiplier applied while Aiming down sights. */ - UPROPERTY() - double TargetingMultiplier = 0.5; - - /** If true then the vertical look axis should be inverted */ - UPROPERTY() - bool bInvertVerticalAxis = false; - - /** If true then the horizontal look axis should be inverted */ - UPROPERTY() - bool bInvertHorizontalAxis = false; - - //////////////////////////////////////////////////////// - // Gamepad Sensitivity -public: - EGBFGamepadSensitivity GetGamepadSensitivityPreset( const FGameplayTag tag ) const - { - if ( auto * sensitivity = GamepadSensitivityMap.Find( tag ) ) - { - return *sensitivity; - } - - return EGBFGamepadSensitivity::Normal; - } - - void SetGamepadSensitivityPreset( const FGameplayTag tag, const EGBFGamepadSensitivity sensitivity ) - { - if ( auto * value = GamepadSensitivityMap.Find( tag ) ) - { - ChangeValueAndDirty( *value, sensitivity ); - } - else - { - auto & new_value = GamepadSensitivityMap.FindOrAdd( tag, EGBFGamepadSensitivity::MAX ); - ChangeValueAndDirty( new_value, sensitivity ); - } - - ApplyInputSensitivity(); - } - - void ApplyInputSensitivity(); - -protected: - UPROPERTY() - TMap< FGameplayTag, EGBFGamepadSensitivity > GamepadSensitivityMap; - - //////////////////////////////////////////////////////// - /// Dirty and Change Reporting -private: - template < typename T > - bool ChangeValueAndDirty( T & CurrentValue, const T & NewValue ) - { - if ( CurrentValue != NewValue ) - { - CurrentValue = NewValue; - bIsDirty = true; - OnSettingChanged.Broadcast( this ); - - return true; - } - - return false; - } - - bool bIsDirty = false; -}; +#pragma once + +#include +#include + +#include "GBFSettingsShared.generated.h" + +class UGBFLocalPlayer; + +UENUM( BlueprintType ) +enum class EGBFColorBlindMode : uint8 +{ + Off, + // Deuteranope (green weak/blind) + Deuteranope, + // Protanope (red weak/blind) + Protanope, + // Tritanope(blue weak / bind) + Tritanope +}; + +UENUM( BlueprintType ) +enum class EGBFAllowBackgroundAudioSetting : uint8 +{ + Off, + AllSounds, + + Num UMETA( Hidden ), +}; + +UENUM( BlueprintType ) +enum class EGBFGamepadSensitivity : uint8 +{ + Invalid = 0 UMETA( Hidden ), + + Slow UMETA( DisplayName = "01 - Slow" ), + SlowPlus UMETA( DisplayName = "02 - Slow+" ), + SlowPlusPlus UMETA( DisplayName = "03 - Slow++" ), + Normal UMETA( DisplayName = "04 - Normal" ), + NormalPlus UMETA( DisplayName = "05 - Normal+" ), + NormalPlusPlus UMETA( DisplayName = "06 - Normal++" ), + Fast UMETA( DisplayName = "07 - Fast" ), + FastPlus UMETA( DisplayName = "08 - Fast+" ), + FastPlusPlus UMETA( DisplayName = "09 - Fast++" ), + Insane UMETA( DisplayName = "10 - Insane" ), + + MAX UMETA( Hidden ), +}; + +UCLASS( BlueprintType ) +class GAMEBASEFRAMEWORK_API UGBFSettingsShared : public ULocalPlayerSaveGame +{ + GENERATED_BODY() + +public: + DECLARE_EVENT_OneParam( UGBFSaveGame, FOnSettingChangedEvent, UGBFSettingsShared * Settings ); + FOnSettingChangedEvent OnSettingChanged; + + UGBFSettingsShared(); + + int32 GetLatestDataVersion() const override; + + bool IsDirty() const + { + return bIsDirty; + } + void ClearDirtyFlag() + { + bIsDirty = false; + } + + /** Creates a temporary settings object, this will be replaced by one loaded from the user's save game */ + static UGBFSettingsShared * CreateTemporarySettings( const UGBFLocalPlayer * local_player ); + + /** Synchronously loads a settings object, this is not valid to call before login */ + static UGBFSettingsShared * LoadOrCreateSettings( const UGBFLocalPlayer * local_player ); + + DECLARE_DELEGATE_OneParam( FGBFOnSettingsLoadedEvent, UGBFSettingsShared * Settings ); + + /** Starts an async load of the settings object, calls Delegate on completion */ + static bool AsyncLoadOrCreateSettings( const UGBFLocalPlayer * local_player, const TSubclassOf< UGBFSettingsShared > & save_game_class, FGBFOnSettingsLoadedEvent delegate ); + + /** Saves the settings to disk */ + void SaveSettings(); + + /** Applies the current settings to the player */ + void ApplySettings(); + + //////////////////////////////////////////////////////// + // Color Blind Options + + UFUNCTION() + EGBFColorBlindMode GetColorBlindMode() const; + UFUNCTION() + void SetColorBlindMode( EGBFColorBlindMode InMode ); + + UFUNCTION() + int32 GetColorBlindStrength() const; + UFUNCTION() + void SetColorBlindStrength( int32 InColorBlindStrength ); + +private: + UPROPERTY() + EGBFColorBlindMode ColorBlindMode = EGBFColorBlindMode::Off; + + UPROPERTY() + int32 ColorBlindStrength = 10; + + //////////////////////////////////////////////////////// + // Gamepad Vibration +public: + UFUNCTION() + bool GetForceFeedbackEnabled() const + { + return bForceFeedbackEnabled; + } + + UFUNCTION() + void SetForceFeedbackEnabled( const bool NewValue ) + { + ChangeValueAndDirty( bForceFeedbackEnabled, NewValue ); + } + +private: + /** Is force feedback enabled when a controller is being used? */ + UPROPERTY() + bool bForceFeedbackEnabled = true; + + //////////////////////////////////////////////////////// + // Gamepad Deadzone +public: + /** Getter for gamepad move stick dead zone value. */ + UFUNCTION() + float GetGamepadMoveStickDeadZone() const + { + return GamepadMoveStickDeadZone; + } + + /** Setter for gamepad move stick dead zone value. */ + UFUNCTION() + void SetGamepadMoveStickDeadZone( const float NewValue ) + { + ChangeValueAndDirty( GamepadMoveStickDeadZone, NewValue ); + } + + /** Getter for gamepad look stick dead zone value. */ + UFUNCTION() + float GetGamepadLookStickDeadZone() const + { + return GamepadLookStickDeadZone; + } + + /** Setter for gamepad look stick dead zone value. */ + UFUNCTION() + void SetGamepadLookStickDeadZone( const float NewValue ) + { + ChangeValueAndDirty( GamepadLookStickDeadZone, NewValue ); + } + +private: + /** Holds the gamepad move stick dead zone value. */ + UPROPERTY() + float GamepadMoveStickDeadZone; + + /** Holds the gamepad look stick dead zone value. */ + UPROPERTY() + float GamepadLookStickDeadZone; + + //////////////////////////////////////////////////////// + // Gamepad Trigger Haptics +public: + UFUNCTION() + bool GetTriggerHapticsEnabled() const + { + return bTriggerHapticsEnabled; + } + UFUNCTION() + void SetTriggerHapticsEnabled( const bool NewValue ) + { + ChangeValueAndDirty( bTriggerHapticsEnabled, NewValue ); + } + + UFUNCTION() + bool GetTriggerPullUsesHapticThreshold() const + { + return bTriggerPullUsesHapticThreshold; + } + UFUNCTION() + void SetTriggerPullUsesHapticThreshold( const bool NewValue ) + { + ChangeValueAndDirty( bTriggerPullUsesHapticThreshold, NewValue ); + } + + UFUNCTION() + uint8 GetTriggerHapticStrength() const + { + return TriggerHapticStrength; + } + UFUNCTION() + void SetTriggerHapticStrength( const uint8 NewValue ) + { + ChangeValueAndDirty( TriggerHapticStrength, NewValue ); + } + + UFUNCTION() + uint8 GetTriggerHapticStartPosition() const + { + return TriggerHapticStartPosition; + } + UFUNCTION() + void SetTriggerHapticStartPosition( const uint8 NewValue ) + { + ChangeValueAndDirty( TriggerHapticStartPosition, NewValue ); + } + +private: + /** Are trigger haptics enabled? */ + UPROPERTY() + bool bTriggerHapticsEnabled = false; + /** Does the game use the haptic feedback as its threshold for judging button presses? */ + UPROPERTY() + bool bTriggerPullUsesHapticThreshold = true; + /** The strength of the trigger haptic effects. */ + UPROPERTY() + uint8 TriggerHapticStrength = 8; + /** The start position of the trigger haptic effects */ + UPROPERTY() + uint8 TriggerHapticStartPosition = 0; + + //////////////////////////////////////////////////////// + // Subtitles + // public: + // UFUNCTION() + // bool GetSubtitlesEnabled() const + // { + // return bEnableSubtitles; + // } + // UFUNCTION() + // void SetSubtitlesEnabled( bool Value ) + // { + // ChangeValueAndDirty( bEnableSubtitles, Value ); + // } + // + // UFUNCTION() + // ESubtitleDisplayTextSize GetSubtitlesTextSize() const + // { + // return SubtitleTextSize; + // } + // UFUNCTION() + // void SetSubtitlesTextSize( ESubtitleDisplayTextSize Value ) + // { + // ChangeValueAndDirty( SubtitleTextSize, Value ); + // ApplySubtitleOptions(); + // } + // + // UFUNCTION() + // ESubtitleDisplayTextColor GetSubtitlesTextColor() const + // { + // return SubtitleTextColor; + // } + // UFUNCTION() + // void SetSubtitlesTextColor( ESubtitleDisplayTextColor Value ) + // { + // ChangeValueAndDirty( SubtitleTextColor, Value ); + // ApplySubtitleOptions(); + // } + // + // UFUNCTION() + // ESubtitleDisplayTextBorder GetSubtitlesTextBorder() const + // { + // return SubtitleTextBorder; + // } + // UFUNCTION() + // void SetSubtitlesTextBorder( ESubtitleDisplayTextBorder Value ) + // { + // ChangeValueAndDirty( SubtitleTextBorder, Value ); + // ApplySubtitleOptions(); + // } + // + // UFUNCTION() + // ESubtitleDisplayBackgroundOpacity GetSubtitlesBackgroundOpacity() const + // { + // return SubtitleBackgroundOpacity; + // } + // UFUNCTION() + // void SetSubtitlesBackgroundOpacity( ESubtitleDisplayBackgroundOpacity Value ) + // { + // ChangeValueAndDirty( SubtitleBackgroundOpacity, Value ); + // ApplySubtitleOptions(); + // } + // + // void ApplySubtitleOptions(); + // + // private: + // UPROPERTY() + // bool bEnableSubtitles = true; + // + // UPROPERTY() + // ESubtitleDisplayTextSize SubtitleTextSize = ESubtitleDisplayTextSize::Medium; + // + // UPROPERTY() + // ESubtitleDisplayTextColor SubtitleTextColor = ESubtitleDisplayTextColor::White; + // + // UPROPERTY() + // ESubtitleDisplayTextBorder SubtitleTextBorder = ESubtitleDisplayTextBorder::None; + // + // UPROPERTY() + // ESubtitleDisplayBackgroundOpacity SubtitleBackgroundOpacity = ESubtitleDisplayBackgroundOpacity::Medium; + + //////////////////////////////////////////////////////// + // Shared audio settings +public: + UFUNCTION() + EGBFAllowBackgroundAudioSetting GetAllowAudioInBackgroundSetting() const + { + return AllowAudioInBackground; + } + UFUNCTION() + void SetAllowAudioInBackgroundSetting( EGBFAllowBackgroundAudioSetting NewValue ); + + void ApplyBackgroundAudioSettings(); + +private: + UPROPERTY() + EGBFAllowBackgroundAudioSetting AllowAudioInBackground = EGBFAllowBackgroundAudioSetting::Off; + + //////////////////////////////////////////////////////// + // Culture / language +public: + /** Gets the pending culture */ + const FString & GetPendingCulture() const; + + /** Sets the pending culture to apply */ + void SetPendingCulture( const FString & NewCulture ); + + // Called when the culture changes. + void OnCultureChanged(); + + /** Clears the pending culture to apply */ + void ClearPendingCulture(); + + bool IsUsingDefaultCulture() const; + + void ResetToDefaultCulture(); + bool ShouldResetToDefaultCulture() const + { + return bResetToDefaultCulture; + } + + void ApplyCultureSettings(); + void ResetCultureToCurrentSettings(); + +private: + /** The pending culture to apply */ + UPROPERTY( Transient ) + FString PendingCulture; + + /* If true, resets the culture to default. */ + bool bResetToDefaultCulture = false; + + //////////////////////////////////////////////////////// + // Gamepad Sensitivity +public: + UFUNCTION() + double GetMouseSensitivityX() const + { + return MouseSensitivityX; + } + UFUNCTION() + void SetMouseSensitivityX( double NewValue ) + { + ChangeValueAndDirty( MouseSensitivityX, NewValue ); + ApplyInputSensitivity(); + } + + UFUNCTION() + double GetMouseSensitivityY() const + { + return MouseSensitivityY; + } + UFUNCTION() + void SetMouseSensitivityY( double NewValue ) + { + ChangeValueAndDirty( MouseSensitivityY, NewValue ); + ApplyInputSensitivity(); + } + + UFUNCTION() + double GetTargetingMultiplier() const + { + return TargetingMultiplier; + } + UFUNCTION() + void SetTargetingMultiplier( double NewValue ) + { + ChangeValueAndDirty( TargetingMultiplier, NewValue ); + ApplyInputSensitivity(); + } + + UFUNCTION() + bool GetInvertVerticalAxis() const + { + return bInvertVerticalAxis; + } + UFUNCTION() + void SetInvertVerticalAxis( bool NewValue ) + { + ChangeValueAndDirty( bInvertVerticalAxis, NewValue ); + ApplyInputSensitivity(); + } + + UFUNCTION() + bool GetInvertHorizontalAxis() const + { + return bInvertHorizontalAxis; + } + UFUNCTION() + void SetInvertHorizontalAxis( bool NewValue ) + { + ChangeValueAndDirty( bInvertHorizontalAxis, NewValue ); + ApplyInputSensitivity(); + } + +private: + /** Holds the mouse horizontal sensitivity */ + UPROPERTY() + double MouseSensitivityX = 1.0; + + /** Holds the mouse vertical sensitivity */ + UPROPERTY() + double MouseSensitivityY = 1.0; + + /** Multiplier applied while Aiming down sights. */ + UPROPERTY() + double TargetingMultiplier = 0.5; + + /** If true then the vertical look axis should be inverted */ + UPROPERTY() + bool bInvertVerticalAxis = false; + + /** If true then the horizontal look axis should be inverted */ + UPROPERTY() + bool bInvertHorizontalAxis = false; + + //////////////////////////////////////////////////////// + // Gamepad Sensitivity +public: + EGBFGamepadSensitivity GetGamepadSensitivityPreset( const FGameplayTag tag ) const + { + if ( auto * sensitivity = GamepadSensitivityMap.Find( tag ) ) + { + return *sensitivity; + } + + return EGBFGamepadSensitivity::Normal; + } + + void SetGamepadSensitivityPreset( const FGameplayTag tag, const EGBFGamepadSensitivity sensitivity ) + { + if ( auto * value = GamepadSensitivityMap.Find( tag ) ) + { + ChangeValueAndDirty( *value, sensitivity ); + } + else + { + auto & new_value = GamepadSensitivityMap.FindOrAdd( tag, EGBFGamepadSensitivity::MAX ); + ChangeValueAndDirty( new_value, sensitivity ); + } + + ApplyInputSensitivity(); + } + + void ApplyInputSensitivity(); + +protected: + UPROPERTY() + TMap< FGameplayTag, EGBFGamepadSensitivity > GamepadSensitivityMap; + + //////////////////////////////////////////////////////// + /// Dirty and Change Reporting +private: + template < typename T > + bool ChangeValueAndDirty( T & CurrentValue, const T & NewValue ) + { + if ( CurrentValue != NewValue ) + { + CurrentValue = NewValue; + bIsDirty = true; + OnSettingChanged.Broadcast( this ); + + return true; + } + + return false; + } + + bool bIsDirty = false; +}; diff --git a/Source/GameBaseFramework/Public/Settings/GBFGameSettingRegistry.h b/Source/GameBaseFramework/Public/Settings/GBFGameSettingRegistry.h index ccc0a4e7..108f1705 100644 --- a/Source/GameBaseFramework/Public/Settings/GBFGameSettingRegistry.h +++ b/Source/GameBaseFramework/Public/Settings/GBFGameSettingRegistry.h @@ -1,7 +1,7 @@ #pragma once #include "GBFGameUserSettings.h" -#include "GameFramework/GBFSaveGame.h" +#include "GameFramework/GBFSettingsShared.h" #include #include @@ -15,7 +15,7 @@ DECLARE_LOG_CATEGORY_EXTERN( LogGBFGameSettingRegistry, Log, Log ); #define GET_SHARED_SETTINGS_FUNCTION_PATH( FunctionOrPropertyName ) \ MakeShared< FGameSettingDataSourceDynamic >( TArray< FString >( { GET_FUNCTION_NAME_STRING_CHECKED( UGBFLocalPlayer, GetSharedSettings ), \ - GET_FUNCTION_NAME_STRING_CHECKED( UGBFSaveGame, FunctionOrPropertyName ) } ) ) + GET_FUNCTION_NAME_STRING_CHECKED( UGBFSettingsShared, FunctionOrPropertyName ) } ) ) #define GET_LOCAL_SETTINGS_FUNCTION_PATH( FunctionOrPropertyName ) \ MakeShared< FGameSettingDataSourceDynamic >( TArray< FString >( { GET_FUNCTION_NAME_STRING_CHECKED( UGBFLocalPlayer, GetLocalSettings ), \