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

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

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



## 모델

### EzWebSocketSession

WebSocketSession<br>

WebSocket 세션은 GS2 서버와 클라이언트 간의 지속적인 연결로, 실시간 양방향 통신을 수행합니다.<br>
서버에 대해 클라이언트 측에서 식별자로 사용자 ID를 등록합니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| connectionId | string |  | ✓ |  |  ~ 128자 | 커넥션 ID<br>이 WebSocket 접속에 할당된 고유 식별자입니다. 알림 송신 시 특정 클라이언트 접속을 식별하는 데 사용됩니다. |
| namespaceName | string |  | ✓ |  |  ~ 128자 | 네임스페이스 이름 |
| userId | string |  | ✓ |  |  ~ 128자 | 사용자ID |

**관련 메서드:**
setUserId - 서버로부터의 푸시 알림을 수신하기 위해 플레이어의 접속을 등록한다


---

### EzFirebaseToken

Firebase 디바이스 토큰<br>

Firebase 디바이스 토큰은 모바일 푸시 알림을 이용할 때 필요합니다.<br>

GS2-Gateway는 게임 내 푸시 알림 기능을 제공하여 매치메이킹 완료 시나 미션 달성 시 푸시 알림을 받을 수 있지만<br>
알림 대상 플레이어가 오프라인인 경우 모바일 푸시 알림으로 전달할 수 있습니다.<br>

이때 알림 대상 디바이스를 특정하여 알림을 보내는 데 사용되는 것이 Firebase 디바이스 토큰입니다.<br>
이름 그대로 Firebase라는 외부 서비스를 이용하므로, 토큰 취득 방법 등 자세한 내용은 Firebase 문서를 확인해 주세요.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| userId | string |  | ✓ |  |  ~ 128자 | 사용자ID |
| token | string |  | ✓ |  |  ~ 1024자 | Firebase Cloud Messaging의 디바이스 토큰<br>클라이언트 디바이스에서 취득한 FCM 등록 토큰입니다. 플레이어가 오프라인이어서 게임 내 WebSocket 알림을 수신할 수 없는 경우, 모바일 푸시 알림을 전달할 특정 디바이스를 식별합니다. 토큰은 디바이스 고유의 값이며 앱을 재설치하거나 데이터를 삭제하면 변경될 수 있습니다. |
| locale | string |  |  |  |  ~ 32자 | 알림 메시지의 로케일<br>이 디바이스에 전달할 알림 메시지의 로케일입니다. `ja` / `en`과 같은 자유 형식의 문자열이며, 정해진 값의 목록으로 제한되지 않습니다. 알림이 모바일 푸시 알림으로 전달될 때, 페이로드가 `{locale, message}` 요소를 가진 `mobile` 배열을 포함하는 JSON인 경우, 이 로케일과 일치하는 요소가 푸시 알림의 본문으로 사용됩니다. 일치하는 요소가 없는 경우에는 `default` 로케일을 가진 요소가, 그것도 없는 경우에는 배열의 첫 번째 요소가 사용됩니다. 페이로드가 해당 형식이 아닌 경우에는 페이로드가 그대로 사용됩니다. 이 항목은 선택 사항이며, 설정되지 않은 경우에는 `default` 요소·첫 번째 요소·페이로드 자체만 적용됩니다. |

**관련 메서드:**
getFirebaseToken - 플레이어에게 등록되어 있는 디바이스 토큰을 가져온다
setFirebaseToken - 모바일 푸시 알림의 전달 대상이 되는 디바이스 토큰을 등록한다
deleteFirebaseToken - 이 단말기로의 모바일 푸시 알림 전달을 중지한다


---

## 메서드

### setUserId

서버로부터의 푸시 알림을 수신하기 위해 플레이어의 접속을 등록한다<br>

현재 WebSocket 접속을 플레이어의 사용자 ID에 연결하여, 서버가 이 클라이언트에 실시간 푸시 알림을 전송할 수 있도록 합니다.<br>
일반적으로 플레이어가 로그인하여 서버에 접속한 직후에 호출합니다. 이 단계를 거치지 않으면 서버는 어느 접속이 어느 플레이어의 것인지 판별할 수 없습니다.<br>
allowConcurrentAccess 플래그로 동일한 플레이어가 여러 디바이스에서 동시에 접속할 수 있는지를 제어합니다:<br>
- true: 여러 동시 접속을 허용(스마트폰과 태블릿 양쪽에서 플레이하는 경우 등)<br>
- false: 플레이어당 1개의 접속만 허용(중복 로그인 방지. 기존 접속은 연결 해제됩니다)<br>
게임의 로그인·초기화 흐름의 일부로 사용합니다. 실시간 채팅 알림, 친구 요청 알림, 매치메이킹 성사 알림 등의 기능을 활성화하는 데 필요합니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름 |
| gameSession | GameSession | | ✓|  |  | GameSession |
| allowConcurrentAccess | bool |  | | true |  | 동시에 다른 클라이언트로부터의 접속을 허용할지 여부 |
| sessionId | string | {allowConcurrentAccess} == false | |  |  ~ 128자 | allowConcurrentAccess를 false로 설정한 경우에도, 기존 접속과 동일한 sessionId라면 접속을 허용하기 위해 지정합니다. |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzWebSocketSession](#ezwebsocketsession) | 갱신한 WebSocket 세션|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Gateway.Namespace(
        namespaceName: "$hash"
    ).Me(
        gameSession: GameSession
    ).WebSocketSession(
    );
    var result = await domain.SetUserIdAsync(
        allowConcurrentAccess: true,
        sessionId: null
    );
    var item = await result.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Gateway.Namespace(
        namespaceName: "$hash"
    ).Me(
        gameSession: GameSession
    ).WebSocketSession(
    );
    var future = domain.SetUserIdFuture(
        allowConcurrentAccess: true,
        sessionId: null
    );
    yield return future;
    if (future.Error != null)
    {
        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->Gateway->Namespace(
        "$hash" // namespaceName
    )->Me(
        GameSession
    )->WebSocketSession(
    );
    const auto Future = Domain->SetUserId(
        true // allowConcurrentAccess
        // sessionId
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        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.gateway.namespace_(
        "$hash"
    ).me(game_session).web_socket_session(
    )

var async_result = await domain.set_user_id(
    true, # allow_concurrent_access
    null # session_id
)
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


---

### deleteFirebaseToken

이 단말기로의 모바일 푸시 알림 전달을 중지한다<br>

플레이어에게 등록되어 있는 FCM 디바이스 토큰을 삭제합니다.<br>
삭제하면 오프라인 시에 도착한 알림이 모바일 푸시 알림으로 전달되지 않게 되며, 게임 내의 WebSocket 알림만 남습니다.<br>
플레이어가 로그아웃할 때(공용 단말기에서 다음 플레이어에게 이전 플레이어 앞으로 온 알림이 도착하지 않도록 하기 위해)나, 게임의 설정 화면에서 플레이어가 알림을 끈 경우에 호출해 주세요.<br>
토큰을 삭제해도 계정의 다른 정보에는 영향이 없습니다. 다시 토큰을 등록하면 모바일 푸시 알림의 수신을 재개할 수 있습니다.

#### Request

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

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzFirebaseToken](#ezfirebasetoken) | 삭제한 Firebase 디바이스 토큰|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Gateway.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).FirebaseToken(
    );
    var result = await domain.DeleteFirebaseTokenAsync(
    );

```

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

```

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

```

**Godot**
```gdscript

var domain = ez.gateway.namespace_(
        "namespace-0001"
    ).me(game_session).firebase_token(
    )

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

var result = async_result.result

```


---

### getFirebaseToken

플레이어에게 등록되어 있는 디바이스 토큰을 가져온다<br>

플레이어에게 현재 등록되어 있는 FCM 디바이스 토큰을 가져옵니다.<br>
이 단말기에서 이미 토큰을 등록했는지 확인하는 데 사용합니다. 예를 들어 알림 권한을 요청하고 토큰을 등록할 필요가 있는지 판단하거나, "알림 설정" 화면에서 현재 상태를 표시하는 데 이용할 수 있습니다.<br>
토큰이 등록되어 있지 않은 경우에는 요청이 not found 에러가 되므로, 그 경우는 "아직 알림 설정이 되어 있지 않다"로 처리해 주세요.<br>
등록되어 있는 토큰은 플레이어가 이전에 사용하던 다른 단말기의 것일 가능성도 있으므로, 이 단말기에서 Firebase SDK로부터 취득한 토큰과 비교한 뒤에 등록을 생략할지 판단해 주세요.

#### Request

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

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzFirebaseToken](#ezfirebasetoken) | Firebase 디바이스 토큰|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Gateway.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).FirebaseToken(
    );
    var item = await domain.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Gateway.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).FirebaseToken(
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;

```

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

```

**Godot**
```gdscript

var domain = ez.gateway.namespace_(
        "namespace-0001"
    ).me(game_session).firebase_token(
    )

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.Gateway.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).FirebaseToken(
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

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

```

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

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

```

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

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

```

**Godot**
```gdscript

var domain = ez.gateway.namespace_(
        "namespace-0001"
    ).me(game_session).firebase_token(
    )

# 이벤트 핸들링 시작
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의 실행에 의해 변화한 것만이 대상이 됩니다.

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

---

### setFirebaseToken

모바일 푸시 알림의 전달 대상이 되는 디바이스 토큰을 등록한다<br>

플레이어의 단말기에서 Firebase SDK로부터 취득한 FCM 디바이스 토큰을 등록(갱신)합니다.<br>
서버로부터의 푸시 알림은 일반적으로 플레이어의 WebSocket 접속을 통해 전달되지만, 플레이어가 오프라인이어서 WebSocket 세션이 없는 경우에는 여기에서 등록한 토큰을 사용하여 모바일 푸시 알림으로 전달됩니다.<br>
이를 통해 게임을 닫아 둔 플레이어에게도 "매치메이킹이 성사되었다", "스태미나가 모두 회복되었다", "친구 신청이 도착했다"와 같은 알림을 보낼 수 있습니다.<br>
로그인 직후 Firebase SDK로부터 토큰을 받은 시점에 호출하고, 나아가 Firebase가 토큰 갱신을 통지할 때마다 호출해 주세요. 토큰은 단말기 고유의 값이며 앱 재설치나 데이터 삭제, Firebase 측의 로테이션에 의해 변경됩니다.<br>
이미 토큰이 등록되어 있는 경우에는 덮어쓰기만 되므로, 게임을 시작할 때마다 호출해도 문제없습니다.<br>
`locale`에는 플레이어의 언어 설정(예를 들어 `ja`나 `en`)을 전달해 주세요. 알림의 페이로드에 여러 언어의 메시지가 포함되어 있는 경우, 해당 로케일과 일치하는 메시지가 모바일 푸시 알림에 사용됩니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| gameSession | GameSession | | ✓|  |  | GameSession |
| token | string |  | ✓|  |  ~ 1024자 | Firebase Cloud Messaging의 디바이스 토큰<br>클라이언트 디바이스에서 취득한 FCM 등록 토큰입니다. 플레이어가 오프라인이어서 게임 내 WebSocket 알림을 수신할 수 없는 경우, 모바일 푸시 알림을 전달할 특정 디바이스를 식별합니다. 토큰은 디바이스 고유의 값이며 앱을 재설치하거나 데이터를 삭제하면 변경될 수 있습니다. |
| locale | string |  | |  |  ~ 32자 | 알림 메시지의 로케일<br>이 디바이스에 전달할 알림 메시지의 로케일입니다. `ja` / `en`과 같은 자유 형식의 문자열이며, 정해진 값의 목록으로 제한되지 않습니다. 알림이 모바일 푸시 알림으로 전달될 때, 페이로드가 `{locale, message}` 요소를 가진 `mobile` 배열을 포함하는 JSON인 경우, 이 로케일과 일치하는 요소가 푸시 알림의 본문으로 사용됩니다. 일치하는 요소가 없는 경우에는 `default` 로케일을 가진 요소가, 그것도 없는 경우에는 배열의 첫 번째 요소가 사용됩니다. 페이로드가 해당 형식이 아닌 경우에는 페이로드가 그대로 사용됩니다. 이 항목은 선택 사항이며, 설정되지 않은 경우에는 `default` 요소·첫 번째 요소·페이로드 자체만 적용됩니다. |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzFirebaseToken](#ezfirebasetoken) | 생성한 Firebase 디바이스 토큰|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Gateway.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).FirebaseToken(
    );
    var result = await domain.SetFirebaseTokenAsync(
        token: "firebase-token-0001",
        locale: null
    );
    var item = await result.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Gateway.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).FirebaseToken(
    );
    var future = domain.SetFirebaseTokenFuture(
        token: "firebase-token-0001",
        locale: null
    );
    yield return future;
    if (future.Error != null)
    {
        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->Gateway->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->FirebaseToken(
    );
    const auto Future = Domain->SetFirebaseToken(
        "firebase-token-0001" // token
        // locale
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        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.gateway.namespace_(
        "namespace-0001"
    ).me(game_session).firebase_token(
    )

var async_result = await domain.set_firebase_token(
    "firebase-token-0001", # token
    null # locale
)
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


---



