> For the complete documentation index, see [llms.txt](/llms.txt)

# GS2-Version SDK for Game Engine API 레퍼런스

게임 엔진용 GS2-Version SDK의 모델 사양과 API 레퍼런스



## 모델

### EzAcceptVersion

승인한 버전<br>

앱 버전이나 에셋 버전처럼 데이터에 연결된 버전이 아니라<br>
동의한 이용약관의 버전처럼 사용자별로 버전 관리가 필요한 엔티티에서 사용합니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| versionName | string |  | ✓ |  |  ~ 128자 | 버전 이름<br>이 승인 레코드가 연결되어 있는 버전 모델의 이름입니다. 사용자의 승인을 특정 버전 모델 정의에 연결합니다. |
| userId | string |  | ✓ |  |  ~ 128자 | 사용자ID |
| version | [EzVersion](#ezversion) |  | ✓ |  |  | 버전<br>사용자가 승인 또는 거부한 버전 번호입니다. "active" 스코프의 버전 모델에서 사용되는 경우, 버전 체크 시 모델의 현재 버전과 비교됩니다. |

**관련 메서드:**
accept - 버전을 승인한다(이용약관에 동의한다)
delete - 버전 승인 기록을 삭제한다
list - 플레이어가 승인 또는 거부한 버전 목록 조회
reject - 버전을 거부한다(선택적 약관을 거절한다)


---

### EzVersionModel

버전 모델<br>

버전 모델에는 로그인은 허용하지만 버전 업그레이드가 가능함을 알리는 경고 버전과, 로그인을 허용하지 않는 에러 버전을 설정할 수 있습니다.<br>

현재 버전을 클라이언트에 신고하도록 할 때, 서명 유무를 지정할 수 있습니다.<br>
서명 있음을 선택한 경우, 클라이언트는 허위 버전을 신고할 수 없게 됩니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| name | string |  | ✓ |  |  ~ 128자 | 버전 모델 이름<br>버전 모델 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| metadata | string |  |  |  |  ~ 2048자 | 메타데이터<br>메타데이터에는 임의의 값을 설정할 수 있습니다.<br>이 값들은 GS2의 동작에는 영향을 주지 않으므로, 게임 내에서 사용하는 정보를 저장하는 용도로 사용할 수 있습니다. |
| warningVersion | [EzVersion](#ezversion) | {type} == "simple" | ✓※ |  |  | 버전 업그레이드를 촉구하는 버전<br>업그레이드 알림을 표시하는 최소 버전 임계값입니다. 클라이언트의 버전이 이 값보다 낮은 경우에도 로그인은 허용되지만 사용자에게 업그레이드가 권장됩니다. 비교는 메이저, 마이너, 마이크로 순으로 계층적으로 수행됩니다.<br><br>※ type이(가) "simple" 이면 필수 |
| errorVersion | [EzVersion](#ezversion) | {type} == "simple" | ✓※ |  |  | 버전 체크에서 에러로 판정되는 버전<br>로그인을 허용하는 최소 버전 임계값입니다. 클라이언트의 버전이 이 값보다 낮으면 버전 체크가 에러로 판정되어 로그인이 차단됩니다. 비교는 메이저, 마이너, 마이크로 순으로 계층적으로 수행됩니다.<br><br>※ type이(가) "simple" 이면 필수 |
| scope | 문자열 열거형<br>enum {<br>"passive",<br>"active"<br>}<br> |  | ✓ |  |  | 판정에 사용할 버전 값의 종류<br>버전 체크에 사용할 버전 값을 얻는 방법을 결정합니다. "passive"는 체크 시점에 클라이언트가 현재 버전을 신고하는 방식이며, "active"는 사용자가 과거에 명시적으로 승인한 버전(이용약관 동의 등)을 사용하는 방식입니다.passive: 클라이언트에서 전송 / active: 과거 명시적으로 승인한 버전 /  |
| currentVersion | [EzVersion](#ezversion) | {type} == "simple" and {scope} == "active" | ✓※ |  |  | 현재 버전<br>이 버전 모델의 최신 버전입니다. "simple" 모드의 "active" 스코프에서만 사용되며, 사용자가 버전 업데이트를 승인·확인할 때 현재 버전을 알립니다.<br><br>※ type이(가) "simple"이고 scope이(가) "active" 이면 필수 |
| needSignature | bool | {scope} == "passive" | ✓※ |  |  | 판정할 버전 값에 서명 검증이 필요한지 여부<br>활성화하면 클라이언트는 버전 신고와 함께 암호 서명을 제공해야 합니다. 이를 통해 클라이언트가 버전 체크를 회피하기 위해 허위 버전을 신고하는 것을 방지합니다. 스코프가 "passive"인 경우에만 적용됩니다.<br><br>※ scope이(가) "passive" 이면 필수 |

**관련 메서드:**
getVersionModel - 특정 버전 체크 정의의 상세 정보 조회
listVersionModels - 버전 체크 정의 목록 조회


**관련 모델:**
EzStatus - 버전 상태



---

### EzVersion

버전<br>

3단계 계층(메이저, 마이너, 마이크로)으로 구성된 버전 번호를 나타냅니다. 버전 비교는 메이저, 마이너, 마이크로 순으로 계층적으로 수행됩니다. 버전 체크의 경고·에러 임계값 정의에 사용됩니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| major | int |  | ✓ |  | 0 ~ 2147483646 | 메이저 버전<br>버전 비교에서 가장 우선순위가 높은 구성 요소입니다. 메이저 버전의 차이는 마이너 버전 및 마이크로 버전보다 우선합니다. |
| minor | int |  | ✓ |  | 0 ~ 2147483646 | 마이너 버전<br>버전 비교에서 두 번째로 우선순위가 높은 구성 요소입니다. 메이저 버전이 동일한 경우에만 비교됩니다. |
| micro | int |  | ✓ |  | 0 ~ 2147483646 | 마이크로 버전<br>버전 비교에서 가장 우선순위가 낮은 구성 요소입니다. 메이저 버전과 마이너 버전이 모두 동일한 경우에만 비교됩니다. |

**관련 메서드:**
accept - 버전을 승인한다(이용약관에 동의한다)
reject - 버전을 거부한다(선택적 약관을 거절한다)


**관련 모델:**
EzAcceptVersion - 승인한 버전
EzVersionModel - 버전 모델
EzStatus - 버전 상태
EzTargetVersion - 검증할 버전



---

### EzStatus

버전 상태<br>

버전 검증 결과를 나타냅니다. 체크에 사용된 버전 모델과, 클라이언트로부터 신고되었거나 사용자 승인으로부터 기록된 현재 버전을 포함합니다. 버전 체크 결과의 일부로 반환되어, 버전이 최신인지, 업그레이드 경고가 필요한지, 차단되는지를 클라이언트에 통지합니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| versionModel | [EzVersionModel](#ezversionmodel) |  | ✓ |  |  | 버전 모델<br>이 버전 체크에 사용된 버전 모델 정의입니다. 체크 결과를 결정한 경고·오류 버전 임계값, 스코프, 기타 설정을 포함합니다. |
| currentVersion | [EzVersion](#ezversion) |  |  |  |  | 현재 버전<br>버전 체크 시 평가된 버전입니다. "passive" 스코프의 경우 클라이언트가 신고한 버전이고, "active" 스코프의 경우 사용자가 과거에 승인한 버전입니다. 버전 정보를 사용할 수 없는 경우 존재하지 않을 수 있습니다. |

**관련 메서드:**
checkVersion - 모든 버전 체크를 한 번에 실행


---

### EzTargetVersion

검증할 버전<br>

버전 체크를 위해 클라이언트가 전송하는 버전 신고를 나타냅니다. 서명 없음 모드에서는 버전을 직접 지정합니다. 서명 있음 모드에서는 변조 방지를 위해 암호 서명과 함께 버전이 바디에 포함됩니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| versionName | string |  | ✓ |  |  ~ 128자 | 버전 모델 이름<br>버전 모델 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| version | [EzVersion](#ezversion) | {signature} == "" | ✓※ |  |  | 버전<br>검증 대상 버전 번호입니다. 서명 검증이 필요하지 않은 경우(서명이 제공되지 않은 경우)에 사용됩니다. 서명이 제공된 경우, 버전은 서명된 바디에서 추출됩니다.<br><br>※ signature이(가) "" 이면 필수 |
| body | string |  |  |  |  ~ 1048576자 | 바디<br>버전 정보를 포함하는 서명된 페이로드입니다. 서명 검증이 활성화된 경우(needSignature가 true)에 사용됩니다. 바디에는 서명과 대조하여 검증할 수 있는 형식으로 버전 데이터가 포함됩니다. |
| signature | string |  |  |  |  ~ 256자 | 서명<br>바디 내용을 검증하기 위한 암호 서명입니다. 제공된 경우, 서버는 버전 모델에 설정된 GS2-Key 암호화 키를 사용하여 서명을 검증한 후 신고된 버전을 받아들입니다. |

**관련 메서드:**
checkVersion - 모든 버전 체크를 한 번에 실행


---

## 메서드

### getVersionModel

특정 버전 체크 정의의 상세 정보 조회<br>

버전 이름을 지정하여 체크 규칙과 임계값을 포함한 상세 정보를 조회합니다.<br>

응답에는 다음이 포함됩니다:<br>
- 스코프: "passive" 체크(앱 버전 — 클라이언트가 버전을 보고)인지 "active" 체크(이용약관 — 플레이어가 명시적으로 동의해야 함)인지<br>
- 경고 버전: 이 임계값을 밑돌면 소프트한 경고가 표시됩니다(예: "새 버전을 사용할 수 있습니다. 업데이트해 주세요.")<br>
- 에러 버전: 이 임계값을 밑돌면 강제 차단이 적용됩니다(예: "플레이를 계속하려면 업데이트가 필요합니다.")<br>
- 현재 버전: 최신 버전입니다(active 스코프의 경우, 플레이어가 동의해야 하는 버전)<br>
- 스케줄 설정: GS2-Schedule과 연동된 경우, 시간 경과에 따라 변화하는 버전 임계값(예: 대규모 업데이트 이후 최소 버전을 단계적으로 인상)<br>

버전 체크의 상세 정보를 표시하거나 커스텀 버전 체크 UI 로직을 구축할 때 사용합니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| versionName | string |  | ✓|  |  ~ 128자 | 버전 모델 이름<br>버전 모델 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzVersionModel](#ezversionmodel) | 버전 모델|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).VersionModel(
        versionName: "version-0001"
    );
    var item = await domain.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).VersionModel(
        versionName: "version-0001"
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Version->Namespace(
        "namespace-0001" // namespaceName
    )->VersionModel(
        "version-0001" // versionName
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

```

**Godot**
```gdscript

var domain = ez.version.namespace_(
        "namespace-0001"
    ).version_model(
        "version-0001"
    )

var async_result = await domain.model()
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


##### 값 변경 이벤트 핸들링




**Unity (UniTask)**
```csharp
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).VersionModel(
        versionName: "version-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).VersionModel(
        versionName: "version-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Version->Namespace(
        "namespace-0001" // namespaceName
    )->VersionModel(
        "version-0001" // versionName
    );
    
    // 이벤트 핸들링 시작
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::Version::Model::FVersionModel> value) {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    Domain->Unsubscribe(CallbackId);

```

**Godot**
```gdscript

var domain = ez.version.namespace_(
        "namespace-0001"
    ).version_model(
        "version-0001"
    )

# 이벤트 핸들링 시작
var callback_id = domain.subscribe_model(func(value):
    # 값이 변화했을 때 호출됨
    # value에는 변경 후의 값이 전달됩니다
    pass
)

# 이벤트 핸들링 정지
domain.unsubscribe_model(callback_id)

```


**⚠️ Warning**

이 이벤트는 SDK가 가진 로컬 캐시의 값이 변경되었을 때 호출됩니다.

로컬 캐시는 SDK가 가진 API의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-Distributor를 통한 스탬프 시트의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-JobQueue의 실행에 의해 변화한 것만이 대상이 됩니다.

따라서 이 방법 이외로 값이 변경된 경우 콜백은 호출되지 않습니다.

---

### listVersionModels

버전 체크 정의 목록 조회<br>

네임스페이스에 정의되어 있는 모든 버전 모델을 조회합니다.<br>
각 버전 모델은 버전 체크 규칙을 나타냅니다. 예를 들어 "앱 버전", "이용약관", "에셋 버전" 등입니다.<br>

GS2-Version은 2가지 유형의 버전 체크를 지원합니다:<br>

1. 앱 버전 체크(passive 스코프): 게임 클라이언트가 자신의 버전(예: "1.2.3")을 보고하고, 서버가 최소 요구 버전을 충족하는지 체크합니다.<br>
- 클라이언트 버전이 "경고" 임계값을 밑돌면 → 업데이트 권장(플레이는 허용)<br>
- 클라이언트 버전이 "오류" 임계값을 밑돌면 → 업데이트 강제(플레이 차단)<br>

2. 이용약관 체크(active 스코프): 플레이어가 현재 버전의 약관에 명시적으로 동의해야 합니다.<br>
- 플레이어가 최신 버전에 동의하지 않은 경우 → 이용약관 다이얼로그 표시<br>
- 플레이어가 이미 동의한 경우 → 체크 통과<br>

어떤 버전 체크가 설정되어 있는지 확인하고, 적절한 시작 흐름(버전 체크 화면, 업데이트 안내, 약관 다이얼로그 등)을 구성할 때 사용합니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| items | [List&lt;EzVersionModel&gt;](#ezversionmodel) | 버전 모델 목록|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    );
    var items = await domain.VersionModelsAsync(
    ).ToListAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    );
    var it = domain.VersionModels(
    );
    List<EzVersionModel> items = new List<EzVersionModel>();
    while (it.HasNext())
    {
        yield return it.Next();
        if (it.Error != null)
        {
            onError.Invoke(it.Error, null);
            break;
        }
        if (it.Current != null)
        {
            items.Add(it.Current);
        }
        else
        {
            break;
        }
    }

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Version->Namespace(
        "namespace-0001" // namespaceName
    );
    const auto It = Domain->VersionModels(
    );
    TArray<Gs2::UE5::Version::Model::FEzVersionModelPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

```


##### 값 변경 이벤트 핸들링




**Unity (UniTask)**
```csharp
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.SubscribeVersionModels(
        () => {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    domain.UnsubscribeVersionModels(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.SubscribeVersionModels(
        () => {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    domain.UnsubscribeVersionModels(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Version->Namespace(
        "namespace-0001" // namespaceName
    );
    
    // 이벤트 핸들링 시작
    const auto CallbackId = Domain->SubscribeVersionModels(
        []() {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    Domain->UnsubscribeVersionModels(CallbackId);

```


**⚠️ Warning**

이 이벤트는 SDK가 가진 로컬 캐시의 값이 변경되었을 때 호출됩니다.

로컬 캐시는 SDK가 가진 API의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-Distributor를 통한 스탬프 시트의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-JobQueue의 실행에 의해 변화한 것만이 대상이 됩니다.

따라서 이 방법 이외로 값이 변경된 경우 콜백은 호출되지 않습니다.

---

### accept

버전을 승인한다(이용약관에 동의한다)<br>

플레이어가 지정된 버전을 승인(동의)했음을 기록합니다.<br>
이는 이용약관, 개인정보 처리방침, 또는 이와 유사한 법적 동의 사항에 대한 "동의합니다" 버튼에 해당합니다.<br>

일반적인 흐름:<br>
1. 플레이어가 최신 버전에 동의하지 않았기 때문에 CheckVersion이 "terms_of_service"에 대해 에러를 반환합니다<br>
2. 게임이 전문을 포함한 이용약관 다이얼로그를 표시합니다<br>
3. 플레이어가 내용을 읽고 "동의합니다"를 탭합니다<br>
4. 게임이 표시된 버전 번호로 Accept를 호출합니다<br>
5. 다음 CheckVersion 호출에서 약관 체크가 통과합니다<br>

중요: 반드시 플레이어에게 실제로 표시된 버전 번호를 전달하세요. 플레이어가 약관을 읽는 동안 서버에서 약관이 업데이트된 경우, 이전 버전을 전달하면 에러가 발생합니다 — 이를 통해 플레이어가 항상 최신 약관에 동의하도록 보장됩니다.<br>

버전을 지정하지 않으면 최신 버전이 사용됩니다. 다만 경쟁 상태(race condition)를 방지하기 위해 버전을 명시적으로 지정하는 것을 권장합니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| gameSession | GameSession | | ✓|  |  | GameSession |
| versionName | string |  | ✓|  |  ~ 128자 | 버전 이름<br>이 승인 레코드가 연결되어 있는 버전 모델의 이름입니다. 사용자의 승인을 특정 버전 모델 정의에 연결합니다. |
| version | [EzVersion](#ezversion) |  | |  |  | 승인한 버전 |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzAcceptVersion](#ezacceptversion) | 승인한 버전|

#### Error

이 API에는 특별한 예외가 정의되어 있습니다.<br>
GS2-SDK for Game Engine에서는 게임 내에서 핸들링이 필요할 것으로 예상되는 에러를, 일반적인 예외에서 파생된 특수화된 예외로 제공하여 다루기 쉽게 하고 있습니다.<br>
일반적인 에러의 종류와 핸들링 방법은 [여기]() 문서를 참고해 주세요.

| 타입 | 베이스 클래스 | 설명 |
| --- | --- | --- |
| AcceptVersionInvalidException | BadRequestException | 승인 처리 도중 서버 버전이 갱신되어 오류가 발생했습니다 |

#### 구현 예제




**Unity (UniTask)**
```csharp

try {
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).AcceptVersion(
        versionName: "eula"
    );
    var result = await domain.AcceptAsync(
        version: new Gs2.Unity.Gs2Version.Model.EzVersion {
            Major = 2,
            Minor = 2,
            Micro = 2,
        }
    );
    var item = await result.ModelAsync();
} catch(Gs2.Gs2Version.Exception.AcceptVersionInvalidException e) {
    // Error as a result of an updated server version during the approval process
}

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).AcceptVersion(
        versionName: "eula"
    );
    var future = domain.AcceptFuture(
        version: new Gs2.Unity.Gs2Version.Model.EzVersion {
            Major = 2,
            Minor = 2,
            Micro = 2,
        }
    );
    yield return future;
    if (future.Error != null)
    {
        if (future.Error is Gs2.Gs2Version.Exception.AcceptVersionInvalidException)
        {
            // Error as a result of an updated server version during the approval process
        }
        onError.Invoke(future.Error, null);
        yield break;
    }
    var future2 = future.Result.ModelFuture();
    yield return future2;
    if (future2.Error != null)
    {
        onError.Invoke(future2.Error, null);
        yield break;
    }
    var result = future2.Result;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Version->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->AcceptVersion(
        "eula" // versionName
    );
    const auto Future = Domain->Accept(
        MakeShared<Gs2::UE5::Version::Model::FEzVersion>()
            ->WithMajor(2)
            ->WithMinor(2)
            ->WithMicro(2)
        ) // version
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        auto e = Future->GetTask().Error();
        if (e->IsChildOf(Gs2::Version::Error::FAcceptVersionInvalidError::Class))
        {
            // Error as a result of an updated server version during the approval process
        }
        return false;
    }

    // 변경된 값 / 결과 값을 취득
    const auto Future2 = Future->GetTask().Result()->Model();
    Future2->StartSynchronousTask();
    if (Future2->GetTask().IsError())
    {
        return Future2->GetTask().Error();
    }
    const auto Result = Future2->GetTask().Result();

```

**Godot**
```gdscript

var domain = ez.version.namespace_(
        "namespace-0001"
    ).me(game_session).accept_version(
        "eula"
    )

var async_result = await domain.accept(
    (Gs2VersionVersion.new()
        .with_major(2)
        .with_minor(2)
        .with_micro(2)) # version
)
if async_result.error != null:
    if async_result.error is Gs2VersionAcceptVersionInvalidException:
        # 승인 처리 도중 서버 버전이 갱신되어 오류가 발생했습니다
        pass
    push_error(str(async_result.error))
    return

var result = async_result.result

```


---

### delete

버전 승인 기록을 삭제한다<br>

지정된 버전 모델에 대한 플레이어의 승인 또는 거부 기록을 삭제합니다.<br>
삭제 후 다음 CheckVersion 호출에서는 플레이어가 이 버전 체크에 한 번도 응답하지 않은 것으로 처리됩니다.<br>

사용 사례:<br>
- 플레이어가 선택적 동의 사항에 대한 결정을 번복할 수 있도록 함(예: 데이터 수집 동의 철회)<br>
- 테스트 또는 디버깅 목적으로 승인 상태를 초기화<br>
- 버전 번호를 변경하지 않고 플레이어가 업데이트된 약관을 다시 읽도록 재승인을 강제<br>

active 스코프 체크(이용약관)의 경우, 승인 기록을 삭제하면 플레이어는 다음 로그인 또는 버전 체크 시 다시 동의를 요청받게 됩니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| gameSession | GameSession | | ✓|  |  | GameSession |
| versionName | string |  | ✓|  |  ~ 128자 | 버전 이름<br>이 승인 레코드가 연결되어 있는 버전 모델의 이름입니다. 사용자의 승인을 특정 버전 모델 정의에 연결합니다. |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzAcceptVersion](#ezacceptversion) | 삭제한 승인 버전|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).AcceptVersion(
        versionName: "eula"
    );
    var result = await domain.DeleteAsync(
    );

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).AcceptVersion(
        versionName: "eula"
    );
    var future = domain.DeleteFuture(
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Version->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->AcceptVersion(
        "eula" // versionName
    );
    const auto Future = Domain->Delete(
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }
    const auto Result = Future->GetTask().Result();

```

**Godot**
```gdscript

var domain = ez.version.namespace_(
        "namespace-0001"
    ).me(game_session).accept_version(
        "eula"
    )

var async_result = await domain.delete(
)
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


---

### list

플레이어가 승인 또는 거부한 버전 목록 조회<br>

현재 플레이어의 모든 버전 승인/거부 기록을 조회합니다.<br>
각 기록에는 플레이어가 어떤 버전 모델에 응답했는지, 어떤 버전을 승인 또는 거부했는지가 포함됩니다.<br>

주로 이용약관 및 개인정보 처리방침 관리에 사용됩니다. 예를 들면:<br>
- 플레이어가 이미 동의한 약관과 그 버전을 표시<br>
- 플레이어가 업데이트된 약관에 다시 동의해야 하는지 확인<br>
- 플레이어가 동의한 내용을 확인할 수 있는 "약관 및 정책" 설정 화면 표시<br>

앱 버전 체크(passive 스코프)에서는 승인 기록이 사용되지 않습니다. 클라이언트가 보고한 버전을 직접 비교하여 체크됩니다. 이 목록에는 active 스코프 체크(플레이어가 명시적으로 승인/거부한 경우)의 기록만 포함됩니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| gameSession | GameSession | | ✓|  |  | GameSession |
| pageToken | string |  | |  |  ~ 1024자 | 데이터 취득을 시작할 위치를 지정하는 토큰 |
| limit | int |  | | 30 | 1 ~ 1000 | 취득할 데이터 건수 |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| items | [List&lt;EzAcceptVersion&gt;](#ezacceptversion) | 승인한 버전 목록|
| nextPageToken | string | 목록의 나머지를 취득하기 위한 페이지 토큰|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var items = await domain.AcceptVersionsAsync(
    ).ToListAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var it = domain.AcceptVersions(
    );
    List<EzAcceptVersion> items = new List<EzAcceptVersion>();
    while (it.HasNext())
    {
        yield return it.Next();
        if (it.Error != null)
        {
            onError.Invoke(it.Error, null);
            break;
        }
        if (it.Current != null)
        {
            items.Add(it.Current);
        }
        else
        {
            break;
        }
    }

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Version->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    );
    const auto It = Domain->AcceptVersions(
    );
    TArray<Gs2::UE5::Version::Model::FEzAcceptVersionPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

```


##### 값 변경 이벤트 핸들링




**Unity (UniTask)**
```csharp
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.SubscribeAcceptVersions(
        () => {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    domain.UnsubscribeAcceptVersions(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.SubscribeAcceptVersions(
        () => {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    domain.UnsubscribeAcceptVersions(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Version->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    );
    
    // 이벤트 핸들링 시작
    const auto CallbackId = Domain->SubscribeAcceptVersions(
        []() {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    Domain->UnsubscribeAcceptVersions(CallbackId);

```


**⚠️ Warning**

이 이벤트는 SDK가 가진 로컬 캐시의 값이 변경되었을 때 호출됩니다.

로컬 캐시는 SDK가 가진 API의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-Distributor를 통한 스탬프 시트의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-JobQueue의 실행에 의해 변화한 것만이 대상이 됩니다.

따라서 이 방법 이외로 값이 변경된 경우 콜백은 호출되지 않습니다.

---

### reject

버전을 거부한다(선택적 약관을 거절한다)<br>

플레이어가 지정된 버전을 거부(거절)했음을 기록합니다.<br>
이는 "거절합니다" 또는 "괜찮습니다" 버튼에 해당하지만, 동의가 필수가 아닌 선택적 약관에 대해서만 사용할 수 있습니다.<br>

이 기능은 버전 모델의 승인 요건이 "optional"로 설정된 경우에만 사용할 수 있습니다. 승인이 필수(mandatory)인 경우, 플레이어는 반드시 동의해야 하며 거부 옵션은 존재하지 않습니다.<br>

선택적 약관의 사용 사례:<br>
- 선택적 데이터 수집 동의: "게임 개선을 위해 이용 데이터를 수집해도 될까요?" → 동의함 / 거절함<br>
- 선택적 마케팅 알림: "프로모션 이메일 수신을 원하십니까?" → 동의함 / 거절함<br>
- 선택적 베타 기능: "실험적인 기능을 사용해 보시겠습니까?" → 동의함 / 거절함<br>

플레이어가 거부하더라도 거부한 사실이 기록되므로, 프롬프트를 확인하고 응답했다는 것을 알 수 있습니다. 다음 CheckVersion에서는 (선택 사항이므로) 버전 체크가 통과하며, 게임은 거부 기록을 확인하여 그에 맞게 동작을 조정할 수 있습니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| gameSession | GameSession | | ✓|  |  | GameSession |
| versionName | string |  | ✓|  |  ~ 128자 | 버전 이름<br>이 승인 레코드가 연결되어 있는 버전 모델의 이름입니다. 사용자의 승인을 특정 버전 모델 정의에 연결합니다. |
| version | [EzVersion](#ezversion) |  | |  |  | 거부한 버전 |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzAcceptVersion](#ezacceptversion) | 거부한 버전|

#### Error

이 API에는 특별한 예외가 정의되어 있습니다.<br>
GS2-SDK for Game Engine에서는 게임 내에서 핸들링이 필요할 것으로 예상되는 에러를, 일반적인 예외에서 파생된 특수화된 예외로 제공하여 다루기 쉽게 하고 있습니다.<br>
일반적인 에러의 종류와 핸들링 방법은 [여기]() 문서를 참고해 주세요.

| 타입 | 베이스 클래스 | 설명 |
| --- | --- | --- |
| AcceptVersionInvalidException | BadRequestException | 승인 처리 도중 서버 버전이 갱신되어 오류가 발생했습니다 |

#### 구현 예제




**Unity (UniTask)**
```csharp

try {
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).AcceptVersion(
        versionName: "version-0001"
    );
    var result = await domain.RejectAsync(
        version: null
    );
    var item = await result.ModelAsync();
} catch(Gs2.Gs2Version.Exception.AcceptVersionInvalidException e) {
    // Error as a result of an updated server version during the approval process
}

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).AcceptVersion(
        versionName: "version-0001"
    );
    var future = domain.RejectFuture(
        version: null
    );
    yield return future;
    if (future.Error != null)
    {
        if (future.Error is Gs2.Gs2Version.Exception.AcceptVersionInvalidException)
        {
            // Error as a result of an updated server version during the approval process
        }
        onError.Invoke(future.Error, null);
        yield break;
    }
    var future2 = future.Result.ModelFuture();
    yield return future2;
    if (future2.Error != null)
    {
        onError.Invoke(future2.Error, null);
        yield break;
    }
    var result = future2.Result;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Version->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->AcceptVersion(
        "version-0001" // versionName
    );
    const auto Future = Domain->Reject(
        // version
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        auto e = Future->GetTask().Error();
        if (e->IsChildOf(Gs2::Version::Error::FAcceptVersionInvalidError::Class))
        {
            // Error as a result of an updated server version during the approval process
        }
        return false;
    }

    // 변경된 값 / 결과 값을 취득
    const auto Future2 = Future->GetTask().Result()->Model();
    Future2->StartSynchronousTask();
    if (Future2->GetTask().IsError())
    {
        return Future2->GetTask().Error();
    }
    const auto Result = Future2->GetTask().Result();

```

**Godot**
```gdscript

var domain = ez.version.namespace_(
        "namespace-0001"
    ).me(game_session).accept_version(
        "version-0001"
    )

var async_result = await domain.reject(
    null # version
)
if async_result.error != null:
    if async_result.error is Gs2VersionAcceptVersionInvalidException:
        # 승인 처리 도중 서버 버전이 갱신되어 오류가 발생했습니다
        pass
    push_error(str(async_result.error))
    return

var result = async_result.result

```


---

### checkVersion

모든 버전 체크를 한 번에 실행<br>

게임 클라이언트의 버전과 플레이어의 약관 동의 상태를, 네임스페이스 내의 모든 버전 모델에 대해 체크합니다.<br>
게임 시작 시 호출하여, 플레이어가 계속 진행할 수 있는지, 업데이트나 약관 동의가 필요한지를 판정하는 메인 API입니다.<br>

일반적인 시작 흐름:<br>
1. 게임이 시작되고, 클라이언트의 현재 버전(앱 버전, 에셋 버전 등)을 전달하여 CheckVersion을 호출<br>
2. 서버가 각 버전 모델을 체크하고, 두 개의 목록을 반환:<br>
- warnings: 체크는 통과했지만 클라이언트가 권장 버전보다 낮음("업데이트가 있습니다" 다이얼로그 표시)<br>
- errors: 체크 실패 — 클라이언트가 너무 오래되었거나 약관에 미동의(플레이어 차단)<br>
3. 오류가 있는 경우, 적절한 화면을 표시:<br>
- 앱 버전 오류 → "App Store / Google Play에서 업데이트해 주세요"라고 표시하고 리다이렉트<br>
- 이용약관 오류 → 약관 다이얼로그를 표시하고, 플레이어가 동의하면 Accept를 호출<br>
4. 경고만 있는 경우(오류 없음), 플레이어를 계속 진행시키되 필요에 따라 업데이트 권장을 표시<br>
5. 경고도 오류도 없으면, 플레이어는 평소대로 게임에 진입<br>

targetVersions 파라미터에는 passive 스코프의 체크(앱 버전 등)용으로 클라이언트의 현재 버전 번호를 전달합니다. active 스코프의 체크(이용약관 등)는 플레이어의 동의 이력을 기반으로 자동으로 평가됩니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| gameSession | GameSession | | ✓|  |  | GameSession |
| targetVersions | [List&lt;EzTargetVersion&gt;](#eztargetversion) |  | | [] | 0 ~ 1000 items | 검증할 버전 목록 |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| projectToken | string | 로그인한 프로젝트 토큰|
| warnings | [List&lt;EzStatus&gt;](#ezstatus) | 버전 검증 결과 경고 목록|
| errors | [List&lt;EzStatus&gt;](#ezstatus) | 버전 검증 결과 오류 목록|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Checker(
    );
    var result = await domain.CheckVersionAsync(
        targetVersions: new List<Gs2.Unity.Gs2Version.Model.EzTargetVersion> {
            new Gs2.Unity.Gs2Version.Model.EzTargetVersion() {
                VersionName = "app",
                Version = 
                new Gs2.Unity.Gs2Version.Model.EzTargetVersion() {
                    Major = 1,
                    Minor = 2,
                    Micro = 3,
                },
            },
            new Gs2.Unity.Gs2Version.Model.EzTargetVersion() {
                VersionName = "asset",
                Version = 
                new Gs2.Unity.Gs2Version.Model.EzTargetVersion() {
                    Major = 1,
                    Minor = 2,
                    Micro = 3,
                },
            },
        }
    );
    var projectToken = result.ProjectToken;
    var warnings = result.Warnings;
    var errors = result.Errors;

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Checker(
    );
    var future = domain.CheckVersionFuture(
        targetVersions: new List<Gs2.Unity.Gs2Version.Model.EzTargetVersion> {
            new Gs2.Unity.Gs2Version.Model.EzTargetVersion() {
                VersionName = "app",
                Version = 
                new Gs2.Unity.Gs2Version.Model.EzTargetVersion() {
                    Major = 1,
                    Minor = 2,
                    Micro = 3,
                },
            },
            new Gs2.Unity.Gs2Version.Model.EzTargetVersion() {
                VersionName = "asset",
                Version = 
                new Gs2.Unity.Gs2Version.Model.EzTargetVersion() {
                    Major = 1,
                    Minor = 2,
                    Micro = 3,
                },
            },
        }
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }
    var projectToken = future.Result.ProjectToken;
    var warnings = future.Result.Warnings;
    var errors = future.Result.Errors;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Version->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Checker(
    );
    const auto Future = Domain->CheckVersion(
        []
        {
            auto v = MakeShared<TArray<TSharedPtr<Gs2::UE5::Version::Model::FEzTargetVersion>>>();
            v->Add(
                MakeShared<Gs2::UE5::Version::Model::FEzTargetVersion>()
                ->WithVersionName(TOptional<FString>("app"))
                ->WithVersion(MakeShared<Gs2::UE5::Version::Model::FEzVersion>() 
                    ->WithMajor(TOptional<int32>(1))
                    ->WithMinor(TOptional<int32>(2))
                    ->WithMicro(TOptional<int32>(3))
                );
            );
            v->Add(
                MakeShared<Gs2::UE5::Version::Model::FEzTargetVersion>()
                ->WithVersionName(TOptional<FString>("asset"))
                ->WithVersion(MakeShared<Gs2::UE5::Version::Model::FEzVersion>() 
                    ->WithMajor(TOptional<int32>(1))
                    ->WithMinor(TOptional<int32>(2))
                    ->WithMicro(TOptional<int32>(3))
                );
            );
            return v;
        }() // targetVersions
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }
    const auto Result = Future->GetTask().Result();
    const auto ProjectToken = Result->ProjectToken;
    const auto Warnings = Result->Warnings;
    const auto Errors = Result->Errors;

```

**Godot**
```gdscript

var domain = ez.version.namespace_(
        "namespace-0001"
    ).me(game_session).checker(
    )

var async_result = await domain.check_version(
    [
        Gs2VersionEzTargetVersion.new()
            .with_version_name("app")
            .with_version(
            Gs2VersionEzVersion.new()
                .with_major(1)
                .with_minor(2)
                .with_micro(3)
            ),
        Gs2VersionEzTargetVersion.new()
            .with_version_name("asset")
            .with_version(
            Gs2VersionEzVersion.new()
                .with_major(1)
                .with_minor(2)
                .with_micro(3)
            ),
    ] # target_versions
)
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


---



