> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 엔터티 핸들

> PlayFab C SDK에서 인증된 플레이어와 타이틀 호출을 위한 PFEntityHandle 자격 증명, 참조 카운팅 및 엔터티 토큰 수명을 관리합니다.

\_\_PFEntityHandle\_\_은 PlayFab 서비스 호출을 하기 위한 기본 자격 증명입니다. 이는 인증된 엔터티(플레이어(title\_player\_account) 또는 타이틀)를 나타내며 SDK가 요청을 승인하는 데 필요한 엔터티 토큰을 보유합니다. 모든 로그인 또는 인증 호출은 \_\_PFEntityHandle\_\_을 반환하며, 모든 서비스 호출에는 이것이 필요합니다.

## 엔터티 핸들 가져오기

엔터티 핸들을 직접 만들지 않습니다. 대신 성공적인 로그인 또는 인증 호출의 출력으로 얻게 됩니다.

**플레이어 로그인(Windows 예제):**

```cpp theme={null}
PFAuthenticationLoginWithXUserRequest request{};
request.createAccount = true;
request.user = userHandle; // XUserHandle from XUserAddAsync

XAsyncBlock async{};
HRESULT hr = PFAuthenticationLoginWithXUserAsync(serviceConfigHandle, &request, &async);
hr = XAsyncGetStatus(&async, true);

PFEntityHandle entityHandle{ nullptr };
size_t bufferSize{};
hr = PFAuthenticationLoginWithXUserGetResultSize(&async, &bufferSize);

std::vector<char> loginResultBuffer(bufferSize);
PFAuthenticationLoginResult const* loginResult{};
hr = PFAuthenticationLoginWithXUserGetResult(
    &async, &entityHandle,
    loginResultBuffer.size(), loginResultBuffer.data(),
    &loginResult, nullptr);
```

**타이틀 엔터티(서버):**

타이틀 엔터티는 사용자 자격 증명 대신 비밀 키로 인증합니다. 반환된 \_\_PFEntityHandle\_\_은 동일한 방식으로 작동하지만, 플레이어가 아닌 타이틀을 나타냅니다. 자세한 내용은 [타이틀 엔터티로 PlayFab 액세스](/services/playfab/sdks/c/server)를 참조하세요.

## 핸들 소유권 및 참조 카운팅

\_\_PFEntityHandle\_\_은 참조 카운트가 지정됩니다. 로그인 호출에서 핸들을 받으면 하나의 참조를 소유합니다. [**PFEntityDuplicateHandle**](/services/playfab/api-references/c/pfentity/functions/pfentityduplicatehandle)로 추가 참조를 만들고 [**PFEntityCloseHandle**](/services/playfab/api-references/c/pfentity/functions/pfentityclosehandle)로 해제할 수 있습니다. 기본 엔터티 오브젝트는 마지막 참조가 닫힐 때만 파괴됩니다.

**규칙:**

* 로그인 `GetResult` 함수 또는 **PFEntityDuplicateHandle** 호출은 반드시 닫아야 하는 핸들을 제공합니다.
* 핸들을 닫아도 동일 엔터티에 대한 다른 핸들이 무효화되지 않습니다.
* [**PFServicesUninitializeAsync**](/services/playfab/api-references/c/pfservices/functions/pfservicesuninitializeasync)를 호출하기 전에 모든 핸들을 닫으세요.

```cpp theme={null}
// Duplicate a handle for another component
PFEntityHandle secondHandle{ nullptr };
HRESULT hr = PFEntityDuplicateHandle(entityHandle, &secondHandle);

// Both handles are independently valid
// ...

// Each owner closes their own handle
PFEntityCloseHandle(secondHandle);
PFEntityCloseHandle(entityHandle);
```

## 엔터티 정보 가져오기

### 엔터티 키

엔터티 키는 엔터티(그 타입 및 ID)를 식별합니다. 두 번 호출하는 패턴을 사용합니다: 먼저 크기를 가져온 다음 데이터를 가져옵니다.

```cpp theme={null}
size_t size{};
HRESULT hr = PFEntityGetEntityKeySize(entityHandle, &size);

std::vector<char> buffer(size);
PFEntityKey const* entityKey{};
hr = PFEntityGetEntityKey(entityHandle, buffer.size(), buffer.data(), &entityKey, nullptr);

// entityKey->type is "title_player_account" for players
// entityKey->id is the entity's unique ID
```

### 엔터티 토큰

엔터티 토큰은 서비스 호출을 승인합니다. SDK는 토큰을 자동으로 관리하지만, 필요한 경우 현재 토큰을 검색할 수 있습니다.

```cpp theme={null}
XAsyncBlock async{};
HRESULT hr = PFEntityGetEntityTokenAsync(entityHandle, &async);
hr = XAsyncGetStatus(&async, true);

size_t size{};
hr = PFEntityGetEntityTokenResultSize(&async, &size);

std::vector<char> buffer(size);
const PFEntityToken* entityToken{};
hr = PFEntityGetEntityTokenResult(&async, buffer.size(), buffer.data(), &entityToken, nullptr);

// entityToken->token is the token string
// entityToken->expiration is the optional expiration time (UTC)
```

### 엔터티 타입 확인

엔터티 키 타입 문자열을 확인하는 대신 [**PFEntityIsTitlePlayer**](/services/playfab/api-references/c/pfentity/functions/pfentityistitleplayer)를 빠른 확인으로 사용합니다:

```cpp theme={null}
bool isTitlePlayer{};
HRESULT hr = PFEntityIsTitlePlayer(entityHandle, &isTitlePlayer);
```

## 플레이어 엔터티 vs. 타이틀 엔터티

플레이어 엔터티와 타이틀 엔터티 모두 \_\_PFEntityHandle\_\_을 사용하지만, 수행할 수 있는 작업이 다릅니다:

|                                                                                                          | 플레이어 엔터티                                         | 타이틀 엔터티                                       |
| -------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | --------------------------------------------- |
| **가져오는 방법**                                                                                              | 로그인 호출(예: `PFAuthenticationLoginWithXUserAsync`) | `PFAuthenticationGetEntityWithSecretKeyAsync` |
| **엔터티 타입**                                                                                               | `title_player_account`                           | `title`                                       |
| [**PFEntityIsTitlePlayer**](/services/playfab/api-references/c/pfentity/functions/pfentityistitleplayer) | `true` 반환                                        | `false` 반환                                    |
| [**PFEntityGetSecretKey**](/services/playfab/api-references/c/pfentity/functions/pfentitygetsecretkey)   | `E_PF_NOSECRETKEY`로 실패                           | 비밀 키 반환                                       |
| **사용 가능한 API**                                                                                           | Client 접두사 및 접두사가 없는 API                         | Server 접두사 및 접두사가 없는 API                      |

접두사가 없는 API(예: Inventory, Leaderboards, Data)는 문서에 별도로 명시되지 않는 한 일반적으로 플레이어 및 타이틀 엔터티 모두에서 호출할 수 있습니다. Client 접두사가 있는 API는 플레이어 전용이며, Server 접두사가 있는 API는 타이틀 전용입니다.

\_\_PFEntityGetSecretKey\_\_는 타이틀 엔터티와 연결된 비밀 키를 검색합니다. 플레이어 엔터티에는 비밀 키가 없기 때문에 실패합니다.

```cpp theme={null}
size_t keySize{};
HRESULT hr = PFEntityGetSecretKeySize(entityHandle, &keySize);
if (SUCCEEDED(hr))
{
    std::vector<char> secretKey(keySize);
    hr = PFEntityGetSecretKey(entityHandle, secretKey.size(), secretKey.data(), nullptr);
}
```

<Note>
  \_\_PFEntityGetSecretKey\_\_는 Windows, Linux 및 macOS 플랫폼에서만 사용할 수 있습니다.
</Note>

## 토큰 이벤트 핸들러

SDK는 엔터티 토큰이 만료되기 전에 자동으로 갱신합니다. 이러한 이벤트를 관찰하기 위해 콜백을 등록할 수 있습니다.

### 토큰 만료됨

자동 갱신에 실패하면(예를 들어, 원래의 로그인 자격 증명이 더 이상 유효하지 않은 경우), SDK는 토큰 만료 이벤트를 발생시킵니다. 새 자격 증명을 제공하고 로그인을 다시 시도하기 위해 핸들러를 등록합니다.

```cpp theme={null}
PFRegistrationToken registrationToken{};
HRESULT hr = PFEntityRegisterTokenExpiredEventHandler(
    nullptr,  // XTaskQueueHandle, or nullptr for default
    nullptr,  // optional context
    [](void* ctx, PFEntityKey const* entityKey)
    {
        // Re-authenticate the player with a fresh credential
        // See relogin.md for a complete example
    },
    &registrationToken);
```

### 토큰 갱신됨

SDK가 백그라운드에서 토큰을 성공적으로 갱신한 시점을 알고 싶다면 토큰 갱신 핸들러를 등록합니다. 이는 정보 제공용입니다—어떠한 조치를 취할 필요는 없습니다.

```cpp theme={null}
PFRegistrationToken registrationToken{};
HRESULT hr = PFEntityRegisterTokenRefreshedEventHandler(
    nullptr,  // XTaskQueueHandle, or nullptr for default
    nullptr,  // optional context
    [](void* ctx, PFEntityKey const* entityKey, const PFEntityToken* newToken)
    {
        // Log the refresh or update cached token references
    },
    &registrationToken);
```

### 등록 및 등록 해제 시기

* **등록**은 SDK 초기화 직후 로그인 전에 일찍 핸들러를 등록합니다. 이렇게 하면 이벤트를 놓치지 않습니다.
* **등록 해제**는 종료 시, 엔터티 핸들을 닫기 전에 핸들러를 등록 해제합니다.

```cpp theme={null}
PFEntityUnregisterTokenExpiredEventHandler(expiredRegistrationToken);
PFEntityUnregisterTokenRefreshedEventHandler(refreshedRegistrationToken);
```

토큰 만료 처리 및 다시 로그인에 대한 전체 안내를 보려면 [토큰 만료 처리](/services/playfab/sdks/c/relogin)를 참조하세요.

## 유틸리티 접근자

엔터티 핸들에서 API 엔드포인트와 타이틀 ID를 검색할 수 있습니다. 이들은 로그인 중에 사용된 \_\_PFServiceConfigHandle\_\_에서 가져옵니다.

```cpp theme={null}
// Get API endpoint
size_t endpointSize{};
HRESULT hr = PFEntityGetAPIEndpointSize(entityHandle, &endpointSize);

std::vector<char> endpoint(endpointSize);
hr = PFEntityGetAPIEndpoint(entityHandle, endpoint.size(), endpoint.data(), nullptr);

// Get title ID
size_t titleIdSize{};
hr = PFEntityGetTitleIdSize(entityHandle, &titleIdSize);

std::vector<char> titleId(titleIdSize);
hr = PFEntityGetTitleId(entityHandle, titleId.size(), titleId.data(), nullptr);
```

## 전체 예제

이 예제는 엔터티 핸들 생성, 중복, 쿼리 및 닫기를 시연합니다:

```cpp theme={null}
#include <playfab/core/PFEntity.h>
#include <playfab/services/PFServices.h>

void EntityHandleExample(PFServiceConfigHandle serviceConfigHandle, XUserHandle userHandle)
{
    //
    // Log in and get an entity handle
    //
    PFAuthenticationLoginWithXUserRequest request{};
    request.createAccount = true;
    request.user = userHandle;

    XAsyncBlock asyncLogin{};
    HRESULT hr = PFAuthenticationLoginWithXUserAsync(serviceConfigHandle, &request, &asyncLogin);
    hr = XAsyncGetStatus(&asyncLogin, true);

    PFEntityHandle entityHandle{ nullptr };
    size_t resultSize{};
    hr = PFAuthenticationLoginWithXUserGetResultSize(&asyncLogin, &resultSize);

    std::vector<char> loginBuffer(resultSize);
    PFAuthenticationLoginResult const* loginResult{};
    hr = PFAuthenticationLoginWithXUserGetResult(
        &asyncLogin, &entityHandle,
        loginBuffer.size(), loginBuffer.data(),
        &loginResult, nullptr);

    //
    // Register token event handlers
    //
    PFRegistrationToken expiredToken{};
    hr = PFEntityRegisterTokenExpiredEventHandler(nullptr, nullptr,
        [](void* ctx, PFEntityKey const* entityKey)
        {
            // Handle re-authentication
        }, &expiredToken);

    PFRegistrationToken refreshedToken{};
    hr = PFEntityRegisterTokenRefreshedEventHandler(nullptr, nullptr,
        [](void* ctx, PFEntityKey const* entityKey, const PFEntityToken* newToken)
        {
            // Log token refresh
        }, &refreshedToken);

    //
    // Duplicate the handle for a subsystem
    //
    PFEntityHandle subsystemHandle{ nullptr };
    hr = PFEntityDuplicateHandle(entityHandle, &subsystemHandle);

    //
    // Query entity info
    //
    bool isTitlePlayer{};
    hr = PFEntityIsTitlePlayer(entityHandle, &isTitlePlayer);

    size_t keySize{};
    hr = PFEntityGetEntityKeySize(entityHandle, &keySize);

    std::vector<char> keyBuffer(keySize);
    PFEntityKey const* entityKey{};
    hr = PFEntityGetEntityKey(entityHandle, keyBuffer.size(), keyBuffer.data(), &entityKey, nullptr);

    //
    // ... make service calls with entityHandle or subsystemHandle ...
    //

    //
    // Cleanup: unregister handlers, then close all handles
    //
    PFEntityUnregisterTokenExpiredEventHandler(expiredToken);
    PFEntityUnregisterTokenRefreshedEventHandler(refreshedToken);

    PFEntityCloseHandle(subsystemHandle);
    PFEntityCloseHandle(entityHandle);
}
```

## API 참조

| 함수                                                                                                                                                 | 설명                                                             |
| -------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
| [PFEntityDuplicateHandle](/services/playfab/api-references/c/pfentity/functions/pfentityduplicatehandle)                                           | 핸들을 복제하고 참조 카운트를 증가시킵니다. 두 핸들 모두 독립적으로 닫아야 합니다.                |
| [PFEntityCloseHandle](/services/playfab/api-references/c/pfentity/functions/pfentityclosehandle)                                                   | 핸들을 닫고 참조 카운트를 감소시킵니다. 마지막 핸들이 닫히면 엔터티가 파괴됩니다.                 |
| [PFEntityGetEntityKeySize](/services/playfab/api-references/c/pfentity/functions/pfentitygetentitykeysize)                                         | 엔터티 키를 저장하는 데 필요한 버퍼 크기를 가져옵니다.                                |
| [PFEntityGetEntityKey](/services/playfab/api-references/c/pfentity/functions/pfentitygetentitykey)                                                 | 엔터티에 대한 엔터티 키(타입 및 ID)를 가져옵니다.                                 |
| [PFEntityGetEntityTokenAsync](/services/playfab/api-references/c/pfentity/functions/pfentitygetentitytokenasync)                                   | 캐시된 엔터티 토큰을 비동기적으로 검색합니다.                                      |
| [PFEntityGetEntityTokenResultSize](/services/playfab/api-references/c/pfentity/functions/pfentitygetentitytokenresultsize)                         | 엔터티 토큰 결과에 필요한 버퍼 크기를 가져옵니다.                                   |
| [PFEntityGetEntityTokenResult](/services/playfab/api-references/c/pfentity/functions/pfentitygetentitytokenresult)                                 | 완료된 PFEntityGetEntityTokenAsync 호출에서 엔터티 토큰을 가져옵니다.            |
| [PFEntityIsTitlePlayer](/services/playfab/api-references/c/pfentity/functions/pfentityistitleplayer)                                               | 엔터티가 title\_player\_account인지 여부를 반환합니다.                       |
| [PFEntityGetSecretKeySize](/services/playfab/api-references/c/pfentity/functions/pfentitygetsecretkeysize)                                         | 비밀 키에 필요한 버퍼 크기를 가져옵니다. 엔터티가 타이틀 엔터티가 아닌 경우 실패합니다.             |
| [PFEntityGetSecretKey](/services/playfab/api-references/c/pfentity/functions/pfentitygetsecretkey)                                                 | 타이틀 엔터티에 대한 비밀 키를 가져옵니다. Windows, Linux 및 macOS에서만 사용할 수 있습니다. |
| [PFEntityGetAPIEndpointSize](/services/playfab/api-references/c/pfentity/functions/pfentitygetapiendpointsize)                                     | API 엔드포인트 문자열에 필요한 버퍼 크기를 가져옵니다.                               |
| [PFEntityGetAPIEndpoint](/services/playfab/api-references/c/pfentity/functions/pfentitygetapiendpoint)                                             | 엔터티의 연결된 서비스 구성에서 API 엔드포인트를 가져옵니다.                            |
| **PFEntityGetTitleIdSize**                                                                                                                         | 타이틀 ID 문자열에 필요한 버퍼 크기를 가져옵니다.                                  |
| **PFEntityGetTitleId**                                                                                                                             | 엔터티의 연결된 서비스 구성에서 타이틀 ID를 가져옵니다.                               |
| [PFEntityRegisterTokenExpiredEventHandler](/services/playfab/api-references/c/pfentity/functions/pfentityregistertokenexpiredeventhandler)         | 자동 토큰 갱신이 실패할 때에 대한 콜백을 등록합니다.                                 |
| [PFEntityUnregisterTokenExpiredEventHandler](/services/playfab/api-references/c/pfentity/functions/pfentityunregistertokenexpiredeventhandler)     | 토큰 만료 콜백을 등록 해제합니다.                                            |
| [PFEntityRegisterTokenRefreshedEventHandler](/services/playfab/api-references/c/pfentity/functions/pfentityregistertokenrefreshedeventhandler)     | SDK가 토큰을 성공적으로 갱신할 때에 대한 콜백을 등록합니다.                            |
| [PFEntityUnregisterTokenRefreshedEventHandler](/services/playfab/api-references/c/pfentity/functions/pfentityunregistertokenrefreshedeventhandler) | 토큰 갱신 콜백을 등록 해제합니다.                                            |

전체 API 참조는 [PFEntity 멤버](/services/playfab/api-references/c/pfentity/pfentity_members)를 참조하세요.

## 참고 항목

* [토큰 만료 처리](/services/playfab/sdks/c/relogin)
* [타이틀 엔터티로 PlayFab 액세스](/services/playfab/sdks/c/server)
* [SDK 수명 주기](/services/playfab/sdks/c/lifecycle)
* [빠른 시작: Windows](/services/playfab/sdks/c/quickstart-gdk)
* [빠른 시작: Win32](/services/playfab/sdks/c/quickstart-win32)


## Related topics

- [타이틀 엔터티의 게임 서버](/ko/services/playfab/sdks/c/server.md)
- [이벤트 파이프라인 튜토리얼](/ko/services/playfab/sdks/c/event-pipeline/eventpipeline-tutorial.md)
- [PlayFab Services SDK - 이벤트 파이프라인](/ko/services/playfab/sdks/c/event-pipeline/eventpipeline.md)
- [PlayFab 독립 실행형 SDK v1에서 Unified SDK v2로 마이그레이션](/ko/services/playfab/sdks/unified-sdk/migrating-from-v1.md)
- [PFEntityDuplicateHandle](/ko/services/playfab/api-references/c/pfentity/functions/pfentityduplicatehandle.md)
