본문 바로가기

사용자 설정과 환경 저장

UGameUserSettings를 확장해 그래픽·오디오·키 바인딩 같은 사용자 옵션을 저장하고 적용합니다.

이전 절들에서는 SaveGame 시스템과 일반 파일 입출력 및 JSON 처리를 통해 게임 데이터를 저장하고 관리하는 방법을 알아보았습니다.

이제 게임에서 매우 중요한 또 다른 종류의 데이터인 사용자 설정(User Settings)과 환경 설정(Environment Settings)을 저장하고 관리하는 방법에 대해 살펴보겠습니다.

여기에는 그래픽 품질, 오디오 볼륨, 키 바인딩, 언어 설정 등 플레이어가 게임 경험을 개인화할 수 있는 모든 옵션이 포함됩니다.

언리얼 엔진은 이를 위해 특별히 고안된 UGameUserSettings 클래스를 제공합니다.


UGameUserSettings 시스템이란?

UGameUserSettings는 현재 로컬 기기의 게임 설정을 저장·로드·적용하는 시스템입니다. 계정별 또는 분할 화면 플레이어별 프로필을 자동으로 나누지는 않습니다.

이 시스템은 각 플레이어의 디바이스에 독립적인 .ini 파일 형태로 설정 데이터를 저장합니다.

UGameUserSettings의 주요 특징

  • 자동 저장/로드: 대부분의 기본 설정(해상도, 그래픽 품질 등)은 엔진에 의해 자동으로 처리됩니다.
  • 플랫폼 독립적: SaveGame 시스템과 마찬가지로, 다양한 플랫폼에서 일관된 방식으로 설정이 관리됩니다.
  • 접근: 정적 함수 UGameUserSettings::GetGameUserSettings()로 로컬 설정 객체를 얻습니다. 커스텀 타입으로 캐스팅한 결과는 검사해야 합니다.
  • 확장성: 기본 설정을 넘어 게임 고유의 커스텀 설정을 추가하고 관리할 수 있습니다.
  • 설정 적용: 변경된 설정을 게임에 즉시 적용하거나, 변경 사항을 임시로 저장했다가 나중에 일괄 적용할 수 있습니다.

커스텀 UGameUserSettings 클래스 생성

대부분의 프로젝트에서는 기본 UGameUserSettings 클래스를 직접 사용하는 대신, 이를 상속받아 게임 고유의 설정 변수를 추가합니다.

MyGameUserSettings.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameUserSettings.h"
#include "InputCoreTypes.h"
#include "MyGameUserSettings.generated.h"

UCLASS()
class MYPROJECT_API UMyGameUserSettings : public UGameUserSettings
{
    GENERATED_BODY()

public:
    UMyGameUserSettings();

    // 싱글톤 패턴처럼 어디서든 쉽게 접근할 수 있는 헬퍼 함수
    UFUNCTION(BlueprintCallable, Category = "Game Settings")
    static UMyGameUserSettings* GetMyGameUserSettings();

    //========================================
    // 커스텀 게임 설정 변수들
    // UPROPERTY로 선언해야 직렬화 대상이 됩니다.
    //========================================

    UPROPERTY(Config) // .ini 파일에 저장될 수 있도록 Config 지정
    float MasterVolume;

    UPROPERTY(Config)
    bool bShowPlayerHealthBar;

    UPROPERTY(Config)
    FString PlayerPreferredLanguage;

    UPROPERTY(Config)
    TArray<FKey> CustomAbilityKeyBinds; // 커스텀 능력 키 바인딩 (예시)

    //========================================
    // 커스텀 설정 제어 함수들
    //========================================

    UFUNCTION(BlueprintCallable, Category = "Game Settings")
    void SetMasterVolume(float NewVolume);

    UFUNCTION(BlueprintPure, Category = "Game Settings")
    float GetMasterVolume() const;

    UFUNCTION(BlueprintCallable, Category = "Game Settings")
    void SetShowPlayerHealthBar(bool bShow);

    UFUNCTION(BlueprintPure, Category = "Game Settings")
    bool GetShowPlayerHealthBar() const;

    UFUNCTION(BlueprintCallable, Category = "Game Settings")
    void SetPlayerPreferredLanguage(const FString& NewLanguage);

    UFUNCTION(BlueprintPure, Category = "Game Settings")
    FString GetPlayerPreferredLanguage() const;

    // 변경 사항을 .ini 파일에 저장 (부모 클래스 함수 오버라이드)
    virtual void SaveSettings() override;

    // 저장된 설정을 로드하거나 기본값을 적용 (부모 클래스 함수 오버라이드)
    virtual void LoadSettings(bool bForceReload = false) override;

    // 설정을 게임에 적용 (그래픽, 사운드 등)
    virtual void ApplySettings(bool bCheckForCommandLineOverrides) override;
};
MyGameUserSettings.cpp
#include "MyGameUserSettings.h"
#include "Internationalization/Internationalization.h"

UMyGameUserSettings::UMyGameUserSettings()
{
    // 기본값 설정
    MasterVolume = 0.75f;
    bShowPlayerHealthBar = true;
    PlayerPreferredLanguage = TEXT("en"); // 기본 언어 영어
    CustomAbilityKeyBinds.Add(EKeys::Q); // 기본 Q 키 바인딩
    CustomAbilityKeyBinds.Add(EKeys::E); // 기본 E 키 바인딩
}

UMyGameUserSettings* UMyGameUserSettings::GetMyGameUserSettings()
{
    // 엔진 설정 클래스 등록과 초기화 상태에 따라 캐스팅은 실패할 수 있습니다.
    return Cast<UMyGameUserSettings>(UGameUserSettings::GetGameUserSettings());
}

void UMyGameUserSettings::SetMasterVolume(float NewVolume)
{
    MasterVolume = FMath::Clamp(NewVolume, 0.0f, 1.0f);
    // 값만 변경합니다. 옵션 UI의 적용 버튼에서 ApplySettings(false)를 호출합니다.
}

float UMyGameUserSettings::GetMasterVolume() const
{
    return MasterVolume;
}

void UMyGameUserSettings::SetShowPlayerHealthBar(bool bShow)
{
    bShowPlayerHealthBar = bShow;
    // UI 관련 설정은 주로 UI 위젯에서 직접 이 변수를 참조하여 처리합니다.
    // 즉시 UI 업데이트를 강제하려면 UI 관리자에게 알림을 보내야 합니다.
}

bool UMyGameUserSettings::GetShowPlayerHealthBar() const
{
    return bShowPlayerHealthBar;
}

void UMyGameUserSettings::SetPlayerPreferredLanguage(const FString& NewLanguage)
{
    PlayerPreferredLanguage = NewLanguage;
    // 값만 변경합니다. 실제 문화권 변경은 ApplySettings에서 시도합니다.
}

FString UMyGameUserSettings::GetPlayerPreferredLanguage() const
{
    return PlayerPreferredLanguage;
}

void UMyGameUserSettings::SaveSettings()
{
    Super::SaveSettings(); // 부모 클래스의 SaveSettings 호출 (실제 파일 저장)
    UE_LOG(LogTemp, Warning, TEXT("MyGameUserSettings: SaveSettings returned."));
}

void UMyGameUserSettings::LoadSettings(bool bForceReload)
{
    Super::LoadSettings(bForceReload); // 부모 클래스의 LoadSettings 호출
    UE_LOG(LogTemp, Warning, TEXT("MyGameUserSettings: LoadSettings returned."));

    // 로드된 후 필요에 따라 추가 초기화/유효성 검사 로직
    MasterVolume = FMath::Clamp(MasterVolume, 0.0f, 1.0f);
}

void UMyGameUserSettings::ApplySettings(bool bCheckForCommandLineOverrides)
{
    // 부모 구현은 기본 설정을 적용하고 SaveSettings도 호출합니다.
    Super::ApplySettings(bCheckForCommandLineOverrides);

    //========================================
    // 커스텀 설정 적용 로직
    //========================================

    // 마스터 볼륨의 실제 오디오 적용은 미구현입니다.
    // 프로젝트의 Sound Class/Mix 또는 오디오 제어 경로에 MasterVolume을 전달해야 합니다.

    // 언어 설정 적용
    if (!FInternationalization::Get().SetCurrentCulture(PlayerPreferredLanguage))
    {
        UE_LOG(LogTemp, Warning, TEXT("Culture was not applied: %s"), *PlayerPreferredLanguage);
    }

    // 키 바인딩 적용 (입력 시스템에 바인딩 로직 필요)
    // Project Settings -> Input -> Action Mappings 또는 Axis Mappings을 C++에서 동적으로 변경하는 것은 복잡합니다.
    // 보통은 FInputBindings와 같은 커스텀 시스템을 구축합니다.

    // 이외의 게임 관련 설정 (예: HUD 체력 바 표시 여부)
    // 이 설정은 주로 HUD 위젯에서 GetShowPlayerHealthBar()를 호출하여 조건부로 표시 여부를 결정합니다.
}

이 예제의 setter는 메모리 값만 바꿉니다. 적용 버튼은 ApplySettings(false)를 호출하며 부모 구현의 저장도 함께 실행됩니다. 취소 UI를 만들려면 편집 전 값을 별도로 보관·복원해야 합니다. RevertVideoMode는 해상도와 전체 화면 모드용이며 커스텀 음량·언어 취소를 대신하지 않습니다.


프로젝트 설정

프로젝트에서 UMyGameUserSettings를 사용하도록 엔진에 알려야 합니다.

이는 DefaultEngine.ini 파일에서 설정합니다.

Config/DefaultEngine.ini 파일을 엽니다. (없다면 프로젝트 루트의 Config 폴더에 생성)

다음 내용을 추가하거나 수정합니다.

[/Script/Engine.Engine]
GameUserSettingsClassName=/Script/MYPROJECT.MyGameUserSettings
  • MYPROJECT는 여러분의 프로젝트 모듈 이름입니다.

이렇게 설정하면 엔진은 게임 시작 시 UMyGameUserSettings의 인스턴스를 자동으로 생성하고 로드/저장 로직을 관리합니다.


사용자 설정 활용 및 적용

C++에서 접근 및 변경

AMyPlayerController 헤더에 SetGameVolume을 선언한 부분 예제입니다. 버튼의 실제 적용 호출은 UI에서 연결해야 합니다.

MyPlayerController.cpp (일부)
#include "MyPlayerController.h"
#include "MyGameUserSettings.h"

void AMyPlayerController::SetGameVolume(float NewVolume)
{
    UMyGameUserSettings* UserSettings = UMyGameUserSettings::GetMyGameUserSettings();
    if (UserSettings)
    {
        UserSettings->SetMasterVolume(NewVolume);
        // 여기서는 편집 값만 변경합니다.
        // 옵션 메뉴의 적용 버튼: UserSettings->ApplySettings(false);
    }
}

블루프린트에서 접근 및 변경

Get My Game User Settings 노드를 사용하여 인스턴스를 얻은 후, 공개된 함수(BlueprintCallable, BlueprintPure)를 호출하여 설정을 읽거나 변경할 수 있습니다.

Apply Settings는 기본 설정 적용과 저장을 포함합니다. Save Settings만 호출하면 커스텀 런타임 적용을 대신하지 않습니다.

설정 파일 위치

UGameUserSettings는 기본적으로 다음 위치에 설정을 저장합니다.

  • Windows 패키지 예시: C:\Users\[사용자명]\AppData\Local\[프로젝트명]\Saved\Config\Windows\GameUserSettings.ini. 에디터와 빌드 대상에 따라 디렉터리가 달라집니다.
  • Android/iOS: 각 플랫폼의 앱 데이터 디렉토리 내에 저장됩니다.

이 파일은 일반 텍스트 .ini 형식으로 되어 있어 직접 열어볼 수 있으며, Config 지정자를 사용한 변수들이 섹션 형태로 저장됩니다.

; GameUserSettings.ini의 커스텀 속성 일부를 나타낸 형식 예시
[/Script/MYPROJECT.MyGameUserSettings]
MasterVolume=0.650000
bShowPlayerHealthBar=True
PlayerPreferredLanguage=ko

설정 값의 저장과 런타임 효과 적용은 다릅니다

setter 메모리 변경과 Super 기본 적용·저장 호출 뒤 문화권 성공/실패를 구분한다. 실제 파일 쓰기 성공은 별도 확인이며 문화권 false 경고에서 앞선 호출 경로가 자동 롤백되지는 않는다.

UNREAL C++ · CH7-4

설정 값의 저장과 런타임 효과 적용은 다릅니다

setter는 메모리 값을 변경합니다. ApplySettings는 부모의 기본 적용·저장 뒤 커스텀 문화권 적용을 시도하지만, 음량·키 재바인딩·HUD 갱신 연결은 아직 구현하지 않았습니다.

기본 저장 뒤 문화권 적용 실패를 구별한다원ApplySettings는부모기본설정적용과저장호출뒤커스텀SetCurrentCulture를시도한다. 성공이면문화권을적용하고실패면경고를남기며앞선저장을자동으로되돌리지않는다. 파일쓰기성공실측이나오디오/키/HUD구현완료를보장하지않는다.ApplySettings 호출편집 값 기준기본 적용 · 저장Super 호출 뒤 시도문화권 적용?반환 bool 확인성공실패문화권 적용됨지원 리소스는 별도경고 · 저장 유지원값 자동 복원 없음
기본 저장 뒤 문화권 적용 실패를 구별한다원ApplySettings는부모기본설정적용과저장호출뒤커스텀SetCurrentCulture를시도한다. 성공이면문화권을적용하고실패면경고를남기며앞선저장을자동으로되돌리지않는다. 파일쓰기성공실측이나오디오/키/HUD구현완료를보장하지않는다.ApplySettings 호출편집 값 기준기본 적용 · 저장Super 호출 뒤 시도문화권 적용?반환 bool 확인성공실패문화권 적용됨지원 리소스는 별도경고 · 저장 유지원값 자동 복원 없음

setter만 호출한 경로와 이 ApplySettings 경로는 다릅니다. 원 오디오·키 적용은 주석이며, 실패 뒤 취소·원값 복원과 재저장도 프로젝트가 별도로 설계합니다.

설정 값과 런타임 효과의 연결
호출·값현재 구현구별할 점
LoadSettings부모에서 설정을 읽고 MasterVolume 범위를 보정합니다.읽기만으로 이 예제의 커스텀 오디오·언어 적용이 실행되지는 않습니다.
ApplySettings부모의 기본 설정 적용·저장 뒤 문화권 변경을 시도합니다.문화권 적용 실패를 기록하지만 앞선 저장을 되돌리지는 않습니다. 유효한 문화권·리소스 정책은 별도입니다.
음량·체력 바음량 값과 표시 플래그를 보관합니다.오디오 제어와 HUD 갱신은 구현하지 않았습니다. 값 변경만으로 해당 효과가 생기지 않습니다.
키 배열Config 속성에 FKey 배열을 보관합니다.배열 저장은 런타임 입력 재바인딩이 아닙니다. 사용하는 입력 시스템에 별도 적용해야 합니다.
LoadSettings
현재 구현: 부모에서 설정을 읽고 MasterVolume 범위를 보정합니다.
구별할 점: 읽기만으로 이 예제의 커스텀 오디오·언어 적용이 실행되지는 않습니다.
ApplySettings
현재 구현: 부모의 기본 설정 적용·저장 뒤 문화권 변경을 시도합니다.
구별할 점: 문화권 적용 실패를 기록하지만 앞선 저장을 되돌리지는 않습니다. 유효한 문화권·리소스 정책은 별도입니다.
음량·체력 바
현재 구현: 음량 값과 표시 플래그를 보관합니다.
구별할 점: 오디오 제어와 HUD 갱신은 구현하지 않았습니다. 값 변경만으로 해당 효과가 생기지 않습니다.
키 배열
현재 구현: Config 속성에 FKey 배열을 보관합니다.
구별할 점: 배열 저장은 런타임 입력 재바인딩이 아닙니다. 사용하는 입력 시스템에 별도 적용해야 합니다.

커스텀 설정 클래스 등록과 캐스트 결과를 확인합니다. 적용 전 편집값 취소는 별도 보관·복원이 필요하며 RevertVideoMode는 음량·언어 취소를 대신하지 않습니다. 저장 로그는 실제 파일/옵션 실행 검증이 아닙니다.

이 예의 조건

  • 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
  • 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.
관계도의 보충 설명
원 도표의 제목·노드·관계·조건·주석
범위원문
관계·조건 설명원 ApplySettings는 부모의 기본 설정 적용과 저장 호출 뒤 커스텀 SetCurrentCulture를 시도한다. 성공하면 문화권이 적용되고, 실패하면 경고를 남기며 앞선 저장을 자동으로 되돌리지 않는다. 파일 쓰기의 실제 성공 여부나 오디오/키/HUD 구현 완료를 보장하지 않는다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
메모리 변경

setter가 설정값을 메모리에 저장한다.

  • 현재: 변경된 메모리 값
  • 파일: 아직 적용/저장 경계 전
  • setter와 최종 환경 적용은 같은 작업이 아니다.
Super 적용·저장

먼저 Super의 기본 적용·저장 호출 경로를 실행하며 실제 파일 성공은 별도로 확인한다.

  • 실행: Super 기본 적용·저장 호출 경로
  • 파일 성공: 실제 쓰기 결과 별도 확인
  • 다음: 문화권 적용 시도
  • 후속 함수 실패가 앞선 부수효과를 자동으로 취소하지 않는다.
문화권 결과

문화권 적용이 false이면 경고하지만 앞선 기본 적용·저장 호출 경로를 자동 롤백하지 않는다.

  • 문화권 결과: false · 경고
  • 앞선 경로 롤백: 자동 처리 없음
  • 전체 설정의 원자적 transaction 성공으로 확대하지 않는다.

설정 값의 저장과 런타임 효과 적용은 다릅니다

setter 메모리 변경과 Super 기본 적용·저장 호출 뒤 문화권 성공/실패를 구분한다. 실제 파일 쓰기 성공은 별도 확인이며 문화권 false 경고에서 앞선 호출 경로가 자동 롤백되지는 않는다.

UNREAL C++ · CH7-4

설정 값의 저장과 런타임 효과 적용은 다릅니다

setter는 메모리 값을 변경합니다. ApplySettings는 부모의 기본 적용·저장 뒤 커스텀 문화권 적용을 시도하지만, 음량·키 재바인딩·HUD 갱신 연결은 아직 구현하지 않았습니다.

기본 저장 뒤 문화권 적용 실패를 구별한다원ApplySettings는부모기본설정적용과저장호출뒤커스텀SetCurrentCulture를시도한다. 성공이면문화권을적용하고실패면경고를남기며앞선저장을자동으로되돌리지않는다. 파일쓰기성공실측이나오디오/키/HUD구현완료를보장하지않는다.ApplySettings 호출편집 값 기준기본 적용 · 저장Super 호출 뒤 시도문화권 적용?반환 bool 확인성공실패문화권 적용됨지원 리소스는 별도경고 · 저장 유지원값 자동 복원 없음
기본 저장 뒤 문화권 적용 실패를 구별한다원ApplySettings는부모기본설정적용과저장호출뒤커스텀SetCurrentCulture를시도한다. 성공이면문화권을적용하고실패면경고를남기며앞선저장을자동으로되돌리지않는다. 파일쓰기성공실측이나오디오/키/HUD구현완료를보장하지않는다.ApplySettings 호출편집 값 기준기본 적용 · 저장Super 호출 뒤 시도문화권 적용?반환 bool 확인성공실패문화권 적용됨지원 리소스는 별도경고 · 저장 유지원값 자동 복원 없음

setter만 호출한 경로와 이 ApplySettings 경로는 다릅니다. 원 오디오·키 적용은 주석이며, 실패 뒤 취소·원값 복원과 재저장도 프로젝트가 별도로 설계합니다.

설정 값과 런타임 효과의 연결
호출·값현재 구현구별할 점
LoadSettings부모에서 설정을 읽고 MasterVolume 범위를 보정합니다.읽기만으로 이 예제의 커스텀 오디오·언어 적용이 실행되지는 않습니다.
ApplySettings부모의 기본 설정 적용·저장 뒤 문화권 변경을 시도합니다.문화권 적용 실패를 기록하지만 앞선 저장을 되돌리지는 않습니다. 유효한 문화권·리소스 정책은 별도입니다.
음량·체력 바음량 값과 표시 플래그를 보관합니다.오디오 제어와 HUD 갱신은 구현하지 않았습니다. 값 변경만으로 해당 효과가 생기지 않습니다.
키 배열Config 속성에 FKey 배열을 보관합니다.배열 저장은 런타임 입력 재바인딩이 아닙니다. 사용하는 입력 시스템에 별도 적용해야 합니다.
LoadSettings
현재 구현: 부모에서 설정을 읽고 MasterVolume 범위를 보정합니다.
구별할 점: 읽기만으로 이 예제의 커스텀 오디오·언어 적용이 실행되지는 않습니다.
ApplySettings
현재 구현: 부모의 기본 설정 적용·저장 뒤 문화권 변경을 시도합니다.
구별할 점: 문화권 적용 실패를 기록하지만 앞선 저장을 되돌리지는 않습니다. 유효한 문화권·리소스 정책은 별도입니다.
음량·체력 바
현재 구현: 음량 값과 표시 플래그를 보관합니다.
구별할 점: 오디오 제어와 HUD 갱신은 구현하지 않았습니다. 값 변경만으로 해당 효과가 생기지 않습니다.
키 배열
현재 구현: Config 속성에 FKey 배열을 보관합니다.
구별할 점: 배열 저장은 런타임 입력 재바인딩이 아닙니다. 사용하는 입력 시스템에 별도 적용해야 합니다.

커스텀 설정 클래스 등록과 캐스트 결과를 확인합니다. 적용 전 편집값 취소는 별도 보관·복원이 필요하며 RevertVideoMode는 음량·언어 취소를 대신하지 않습니다. 저장 로그는 실제 파일/옵션 실행 검증이 아닙니다.

이 예의 조건

  • 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
  • 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.

관계도의 보충 설명

원 도표의 제목·노드·관계·조건·주석
범위원문
관계·조건 설명원 ApplySettings는 부모의 기본 설정 적용과 저장 호출 뒤 커스텀 SetCurrentCulture를 시도한다. 성공하면 문화권이 적용되고, 실패하면 경고를 남기며 앞선 저장을 자동으로 되돌리지 않는다. 파일 쓰기의 실제 성공 여부나 오디오/키/HUD 구현 완료를 보장하지 않는다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
메모리 변경

setter가 설정값을 메모리에 저장한다.

  • 현재: 변경된 메모리 값
  • 파일: 아직 적용/저장 경계 전
  • setter와 최종 환경 적용은 같은 작업이 아니다.
Super 적용·저장

먼저 Super의 기본 적용·저장 호출 경로를 실행하며 실제 파일 성공은 별도로 확인한다.

  • 실행: Super 기본 적용·저장 호출 경로
  • 파일 성공: 실제 쓰기 결과 별도 확인
  • 다음: 문화권 적용 시도
  • 후속 함수 실패가 앞선 부수효과를 자동으로 취소하지 않는다.
문화권 결과

문화권 적용이 false이면 경고하지만 앞선 기본 적용·저장 호출 경로를 자동 롤백하지 않는다.

  • 문화권 결과: false · 경고
  • 앞선 경로 롤백: 자동 처리 없음
  • 전체 설정의 원자적 transaction 성공으로 확대하지 않는다.

예시: 편집·저장·효과 적용을 따로 따라가기

등록한 커스텀 설정 클래스로 캐스트가 성공했고 MasterVolume이 0.75인 상태에서 SetMasterVolume(1.4)를 호출하면 메모리 값은 1로 제한됩니다. setter만으로 파일 저장이나 실제 사운드 변경은 이루어지지 않습니다. SaveSettings를 호출하면 저장 경로를 실행하지만, 원 코드에는 오디오 제어로 값을 보내는 동작이 없습니다. ApplySettings(false)도 주석인 오디오·키 적용을 자동 완성하지 않습니다.

문화권 실패와 취소 상태 판단하기

편집 전 언어값은 en이었고, 새 문자열을 설정한 뒤 ApplySettings(false)를 호출했습니다. 부모의 기본 적용·저장 경로가 실행됐고 SetCurrentCulture는 false를 반환했다고 가정합니다. 원 코드가 저장한 언어값을 자동으로 en으로 되돌릴까요? 또 음량 편집을 취소하고 싶다면 RevertVideoMode만 호출해도 되는지 설명하세요.

원 호출 순서와 구현 범위로 풀이하기

문화권 변경 실패는 경고를 남기지만 앞서 설정한 언어 문자열을 되돌리거나 이미 실행한 저장을 롤백하지 않습니다. 이 호출 순서는 원 코드에 명시된 경로이며 실제 파일 저장과 문화권 리소스 적용은 별도로 확인해야 합니다. 취소하려면 편집 전 커스텀 값의 보관·복원과, 이미 적용·저장했다면 그 값을 다시 반영할 정책을 준비합니다. RevertVideoMode는 해상도·전체 화면 모드용이므로 커스텀 음량과 언어의 취소를 대신하지 않습니다.

설정 파일은 사용자가 수정할 수 있으므로 로드 후 값 검증이 필요합니다. 이 예제는 음량 범위만 보정하며, 실제 오디오·입력 시스템과 UI 갱신 연결은 프로젝트에서 완성해야 합니다.