다음을 통해 공유


플레이어 인벤토리

요구 사항

플레이어 인벤토리를 사용하려면 타이틀에 맞게 정의된 카탈로그가 있어야 합니다. 자세한 내용은 카탈로그 자습서를 참조하세요.

참고 항목

원하는 경우 카탈로그의 저장소를 정의할 수도 있습니다.

카탈로그는 게임에서 사용할 수 있는 모든 아이템의 목록인 반면, 저장소는 고유한 가격 정보 옵션이 있는 카탈로그의 아이템 하위 집합입니다.

카탈로그마다 다양한 저장소를 정의할 수 있으므로 사용자 세분화 또는 다른 요소를 기반으로 플레이어에게 표시할 고유한 아이템 집합을 가질 수 있습니다.

게임 관리자 또는 관리자 SetCatalogItems 또는 UpdateCatalogItems API 호출을 통해 카탈로그를 정의했으면 클라이언트 및 서버에서 다양한 인벤토리 API 호출을 사용할 수 있게 됩니다.

API 개요

모든 인벤토리 API 호출은 서버 권한이 있고 안전합니다. 제대로 사용하면 고객은 획득하지 못한 아이템을 속이거나 획득할 수 없습니다.

클라이언트:

서버:

아래 예에서는 이러한 API 메서드를 호출하는 코드 블록을 보여 주고 플레이어 인벤토리에 대한 기본적인 사용 사례를 만듭니다.

참고 항목

참조를 위해 이러한 예제는 PlayFab 기능을 보여 주기 위해 예제로 만들었던 Unicorn Battle이라는 게임에서 가져왔습니다.

아래에서 사용된 AU 가상 통화는 전투하는 몬스터가 획득하는 무료 통화인 골드입니다(통화 자습서 참조).

시작하기 전에 이 가이드의 대부분의 예제에서 사용하고 재사용할 몇 가지 유틸리티 함수를 정의합니다.

// **** Shared example utility functions ****

// This is typically NOT how you handle success
// You will want to receive a specific result-type for your API, and utilize the result parameters
void LogSuccess(PlayFabResultCommon result) {
    var requestName = result.Request.GetType().Name;
    Debug.Log(requestName + " successful");
}

// Error handling can be very advanced, such as retry mechanisms, logging, or other options
// The simplest possible choice is just to log it
void LogFailure(PlayFabError error) {
    Debug.LogError(error.GenerateErrorReport());
}

클라이언트 전용 예제: 상태 포션 구입 및 사용

클라이언트 API 호출 순서: PurchaseItem, GetUserInventory, ConsumeItem

먼저 카탈로그에서 아이템을 정의하는 것으로 시작해야 합니다.

PlayFab - 경제 - 카탈로그 아이템 편집

상태 포션에 대한 CatalogItem 요구 사항은 다음과 같습니다.

  • PurchaseItem은(는) 양수 아이템 가격(5 AU)이 필요합니다.
  • ConsumeItem은(는) 아이템이 Consumable 상태이고 아이템 개수(3)가 양수여야 합니다.
  • 구매하는 플레이어는 가상 통화 잔액에 5AU가 있어야 합니다.

각 호출에 대한 코드는 아래에 제공됩니다.

void MakePurchase() {
    PlayFabClientAPI.PurchaseItem(new PurchaseItemRequest {
        // In your game, this should just be a constant matching your primary catalog
        CatalogVersion = "CharacterClasses",
        ItemId = "MediumHealthPotion",
        Price = 5,
        VirtualCurrency = "AU"
    }, LogSuccess, LogFailure);
}

void GetInventory() {
    PlayFabClientAPI.GetUserInventory(new GetUserInventoryRequest(), LogSuccess, LogFailure);
}

void ConsumePotion() {
    PlayFabClientAPI.ConsumeItem(new ConsumeItemRequest {
        ConsumeCount = 1,
        // This is a hex-string value from the GetUserInventory result
        ItemInstanceId = "potionInstanceId"
    }, LogSuccess, LogFailure);
}

예: 플레이어가 부여되고 컨테이너를 엽니다.

API 호출 순서:

먼저 카탈로그에 정의된 컨테이너로 시작해야 합니다. 이 예의 컨테이너의 경우 CrystalContainer를 선택했습니다.

이 예에서는 UnlockContainerInstance 호출이 성공하기 위해 플레이어 인벤토리에 있어야 하는 선택적 항목인 키를 사용하여 컨테이너를 여는 방법도 보여줍니다.

PlayFab - 경제 - 카탈로그 컨테이너 편집

이 예에서 CrystalContainerCatalogItem 요구 사항에는 다음이 포함됩니다.

  • CrystalContainer컨테이너로 정의해야 합니다.

  • 선택에 따라 컨테이너키 아이템을 정의할 수 있고 그 후 이 아이템으로 컨테이너의 잠금을 해제해야 합니다. 이 경우에는 CrystalKey입니다.

  • 컨테이너모두 사용한 후에 플레이어 인벤토리에서 제거할 수 있도록 양수의 사용 개수를 가진 소모성 콘텐츠인 것이 좋습니다.

서버 코드

void GrantItem() {
    PlayFabServerAPI.GrantItemsToUser(new GrantItemsToUserRequest {
        // In your game, this should just be a constant
        CatalogVersion = "CharacterClasses",
        // Servers must define which character they're modifying in every API call
        PlayFabId = "playFabId",
        ItemIds = new List<string> { "CrystalContainer" }
    }, LogSuccess, LogFailure);
}

클라이언트 코드

void OpenContainer() {
    PlayFabClientAPI.UnlockContainerInstance(new UnlockContainerInstanceRequest {
        // In your game, this should just be a constant matching your primary catalog
        CatalogVersion = "CharacterClasses",
        ContainerItemInstanceId = "containerInstanceId",
        KeyItemInstanceId = "keyInstanceId"
    }, LogSuccess, LogFailure);
}

소모성 키 및 컨테이너

이전 예에서는 단순히 권장 사항이긴 하지만 키 및/또는 컨테이너가 소모성 콘텐츠일 것을 권장했습니다.

그러나 컨테이너 및 해당 키(있는 경우)가 소모성이 아닌 경우 컨테이너를 무한히 열 수 있으므로 매번 해당 콘텐츠를 플레이어에게 수여합니다.

플레이어 인벤토리 용량은 무한하지 않기때문에 이러한 패턴은 지양해야 합니다. 소모성 컨테이너의 잠금이 해제되어 있는 경우 해당 컨테이너 및 사용했던 소모성 키의 사용 개수가 모두 자동으로 감소할 것입니다. 사용 개수가 0에 도달할 때까지 플레이어 인벤토리에서 개수를 제거합니다.

실행 가능한 옵션

소모성 컨테이너, 없음: 가장 기본적인 패턴으로, 컨테이너가 열리면 소모되고 키는 없습니다.

소모성 컨테이너, 소모성 키: 간단한 잠긴 컨테이너 케이스로 플레이어가 키를 가지고 컨테이너를 열 수 있습니다. 둘 다 사용되며 플레이어에게 키 사용 개수가 남아 있는 경우에만 컨테이너를 열 수 있습니다.

지속성 컨테이너, 소모성 키: 플레이어가 키를 찾을 때마다 컨테이너를 열 수 있습니다. 키가 소모되며, 키를 사용할 수 있는 횟수가 남아 있는 동안만 컨테이너가 열립니다.

소모성 컨테이너, 지속성 키: 플레이어가 키 아이템에 대한 모든 컨테이너를 열 수 있는 키를 보관할 수 있습니다. 컨테이너가 소모되지만 플레이어가 키를 가지고 나중에 컨테이너를 계속 열 수 있습니다.

예: 플레이어로부터 인벤토리 아이템 구입

프로세스가 게임에 특화되어 있으므로 플레이어로부터 인벤토리 아이템을 다시 구입하기 위한 내장된 API는 없습니다. 그러나 기존 API 메서드를 사용하여 고유한 SellItem 환경을 만들 수 있습니다.

  • PlayFab 서버 API RevokeInventoryItem**을 통해 인벤토리 아이템을 제거할 수 있습니다.

  • PlayFab 서버 API AddUserVirtualCurrency**는 적당한 양의 가상 통화를 반환할 수 있습니다. 현재 PlayFab API 메서드를 통해 현금을 반환할 수는 없습니다.

참고 항목

아이템과 가상 통화는 밀접한 관련이 있습니다. 자세한 내용은 통화 자습서를 참조하십시오.

다음 CloudScript 기능은 설명된 두 서버 호출을 하나의 클라이언트 액세스 가능 호출로 통합합니다.

var SELL_PRICE_RATIO = 0.75;
function SellItem_internal(soldItemInstanceId, requestedVcType) {
    var inventory = server.GetUserInventory({ PlayFabId: currentPlayerId });
    var itemInstance = null;
    for (var i = 0; i < inventory.Inventory.length; i++) {
        if (inventory.Inventory[i].ItemInstanceId === soldItemInstanceId)
            itemInstance = inventory.Inventory[i];
    }
    if (!itemInstance)
        throw "Item instance not found"; // Protection against client providing incorrect data
    var catalog = server.GetCatalogItems({ CatalogVersion: itemInstance.CatalogVersion });
    var catalogItem = null;
    for (var c = 0; c < catalog.Catalog.length; c++) {
        if (itemInstance.ItemId === catalog.Catalog[c].ItemId)
            catalogItem = catalog.Catalog[c];
    }
    if (!catalogItem)
        throw "Catalog Item not found"; // Title catalog consistency check (You should never remove a catalog/catalogItem if any player owns that item
    var buyPrice = 0;
    if (catalogItem.VirtualCurrencyPrices.hasOwnProperty(requestedVcType))
        buyPrice = catalogItem.VirtualCurrencyPrices[requestedVcType];
    if (buyPrice <= 0)
        throw "Cannot redeem this item for: " + requestedVcType; // The client requested a virtual currency which doesn't apply to this item
    // Once we get here all safety checks are passed - Perform the sell
    var sellPrice = Math.floor(buyPrice * SELL_PRICE_RATIO);
    server.AddUserVirtualCurrency({ PlayFabId: currentPlayerId, Amount: sellPrice, VirtualCurrency: requestedVcType });
    server.RevokeInventoryItem({ PlayFabId: currentPlayerId, ItemInstanceId: soldItemInstanceId });
}

handlers.SellItem = function (args) {
    if (!args || !args.soldItemInstanceId || !args.requestedVcType)
        throw "Invalid input parameters, expected soldItemInstanceId and requestedVcType";
    SellItem_internal(args.soldItemInstanceId, args.requestedVcType);
};

모범 사례

  • 변경하기 전에 클라이언트가 입력한 모든 정보가 유효한지 확인해야 합니다.

  • CloudScript는 원자성이 아니므로 호출 순서가 중요합니다. AddUserVirtualCurrency는 성공하고 RevokeInventoryItem은 실패할 수 있습니다.

아무런 보상 없이 플레이어가 가진 것을 빼앗기 보다는 이 프로세스에서 플레이어가 획득하지 않은 것을 주는 것이 좋습니다.

그런 다음 클라이언트에서 이 CloudScript 함수에 액세스할 수 있습니다.

void SellItem()
{
    PlayFabClientAPI.ExecuteCloudScript(new ExecuteCloudScriptRequest
    {
        // This must match "SellItem" from the "handlers.SellItem = ..." line in the CloudScript file
        FunctionName = "SellItem",
        FunctionParameter = new Dictionary<string, string>{
            // This is a hex-string value from the GetUserInventory result
            { "soldItemInstanceId", "sellItemInstanceId" },
            // Which redeemable virtual currency should be used in your game
            { "requestedVcType", "AU" },
        }
    }, LogSuccess, LogFailure);
}