Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
cybtachyon committed May 26, 2023
1 parent 12a2846 commit a1cd11a
Show file tree
Hide file tree
Showing 391 changed files with 81,401 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Samples/Unity/PlayFabEconomyV2/.vsconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"version": "1.0",
"components": [
"Microsoft.VisualStudio.Workload.ManagedGame"
]
}
285 changes: 285 additions & 0 deletions Samples/Unity/PlayFabEconomyV2/Assets/AndroidIAPExample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
using Mono.Cecil.Cil;
using PlayFab;
using PlayFab.ClientModels;
using PlayFab.EconomyModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Unity.Burst.Intrinsics;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Purchasing;
using UnityEngine.Purchasing.Extension;
using UnityEngine.Purchasing.Security;

public class AndroidIAPExample : MonoBehaviour, IDetailedStoreListener
{
/**
* True if the Store Controller, extensions, and Catalog are set.
*/
public bool IsInitialized
{
get
{
return m_StoreController != null && Catalog != null;
}
}

/**
* Returns false as this is just sample code.
*
* @todo Implement this functionality for your game.
*/
public bool UserHasExistingSave
{
get
{
return false;
}
}

// Items list, configurable via inspector.
private List<PlayFab.EconomyModels.CatalogItem> Catalog;

private static IStoreController m_StoreController;

public void BuyProductByID(string productID)
{
if (!IsInitialized) throw new Exception("IAP Service is not initialized!");

m_StoreController.InitiatePurchase(productID);
}

private void InitializePurchasing()
{
if (IsInitialized) return;

var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance(AppStore.GooglePlay));

foreach (var item in Catalog)
{
var googlePlayItemId = item.AlternateIds.FirstOrDefault(item => item.Type == "GooglePlay").Value;
if (googlePlayItemId.IsUnityNull()) {
builder.AddProduct(googlePlayItemId, ProductType.Consumable);
}
}

UnityPurchasing.Initialize(this, builder);
}

/**
* Attempts to log the player in via the Android Device ID.
*/
private void Login()
{
// Best practice is to soft-login with a unique ID, then prompt the player to finish
// creating a PlayFab account in order to retrive cross-platform saves or other benefits.
if (UserHasExistingSave)
{
// @todo Integrate this with the save system.
LoginWithPlayFabRequest loginWithPlayFabRequest = new()
{
Username = "",
Password = ""
};
PlayFabClientAPI.LoginWithPlayFab(loginWithPlayFabRequest, OnRegistration, OnPlayFabError);
return;
}

// AndroidDeviceID will prompt for permissions on newer devices.
// Using a non-device specific GUID and saving to a local file
// is a better approach. PlayFab does allow you to link multiple
// Android device IDs to a single PlayFab account.
PlayFabClientAPI.LoginWithAndroidDeviceID(new LoginWithAndroidDeviceIDRequest()
{
CreateAccount = true,
AndroidDeviceId = SystemInfo.deviceUniqueIdentifier
}, result => {
RefreshIAPItems();
}, error => Debug.LogError(error.GenerateErrorReport()));
}

public void OnGUI()
{
// Support high-res devices.
GUI.matrix = Matrix4x4.TRS(new Vector3(0, 0, 0), Quaternion.identity, new Vector3(3, 3, 3));

if (!IsInitialized)
{
GUILayout.Label("Initializing IAP and logging in...");
return;
}

// Draw a purchase menu for each catalog item.
foreach (var item in Catalog)
{
if (GUILayout.Button("Buy " + item.Description))
{
BuyProductByID(item.AlternateIds.FirstOrDefault(item => item.Type == "GooglePlay").Value);
}
}
}

private void OnRegistration(LoginResult result)
{
PlayFabSettings.staticPlayer.ClientSessionTicket = result.SessionTicket;
}

public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
m_StoreController = controller;
}

public void OnInitializeFailed(InitializationFailureReason error)
{
Debug.Log("OnInitializeFailed InitializationFailureReason:" + error);
}

public void OnInitializeFailed(InitializationFailureReason error, string message)
{
Debug.Log("OnInitializeFailed InitializationFailureReason:" + error + message);
}

private void OnPlayFabError(PlayFabError error)
{
Debug.LogError(error.GenerateErrorReport());
}

public void OnPurchaseFailed(UnityEngine.Purchasing.Product product, PurchaseFailureReason failureReason)
{
Debug.Log(string.Format("OnPurchaseFailed: FAIL. Product: '{0}', PurchaseFailureReason: {1}", product.definition.storeSpecificId, failureReason));
}

public void OnPurchaseFailed(UnityEngine.Purchasing.Product product, PurchaseFailureDescription failureDescription)
{
Debug.Log(string.Format("OnPurchaseFailed: FAIL. Product: '{0}', PurchaseFailureReason: {1}", product.definition.storeSpecificId, failureDescription));
}

/**
* Callback for Store purchases.
*
* @note This code does not account for purchases that were pending and are
* delivered on application start. Production code should account for these
* cases.
*
* @see https://docs.unity3d.com/Packages/[email protected]/api/UnityEngine.Purchasing.PurchaseProcessingResult.html
*/
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs purchaseEvent)
{
if (!IsInitialized)
{
return PurchaseProcessingResult.Complete;
}

if (purchaseEvent.purchasedProduct == null)
{
Debug.LogWarning("Attempted to process purchase with unknown product. Ignoring.");
return PurchaseProcessingResult.Complete;
}

if (string.IsNullOrEmpty(purchaseEvent.purchasedProduct.receipt))
{
Debug.LogWarning("Attempted to process purchase with no receipt. Ignoring.");
return PurchaseProcessingResult.Complete;
}

RedeemGooglePlayInventoryItemsRequest request = new()
{
Purchases = new List<GooglePlayProductPurchase> {
new GooglePlayProductPurchase() {
ProductId = purchaseEvent.purchasedProduct.receipt,
Token = GooglePurchase.FromJson(purchaseEvent.purchasedProduct.receipt).PayloadData.signature
}
}
};
PlayFabEconomyAPI.RedeemGooglePlayInventoryItems(request, result => Debug.Log("Validation successful!"),
error => Debug.Log("Validation failed: " + error.GenerateErrorReport()));

return PurchaseProcessingResult.Complete;
}

private async void RefreshIAPItems()
{
SearchItemsRequest request = new()
{
Count = 50,
Store = new StoreReference() { Id = "Default" }
};
SearchItemsResponse response = new();
PlayFabEconomyAPIAsync asyncAPI = new();
do
{
response = await asyncAPI.searchItemsAsync(request);
Catalog.AddRange(response.Items);
} while (response.ContinuationToken != "");
InitializePurchasing();
}

// Start is called before the first frame update
public void Start()
{
Login();
}

// Update is called once per frame
public void Update() { }
}

// Utility classes for the sample.

public class PlayFabEconomyAPIAsync
{
private TaskCompletionSource<SearchItemsResponse> searchItemsAsyncTaskSource = new();

public void OnSearchItemsRequestComplete(SearchItemsResponse response)
{
searchItemsAsyncTaskSource.SetResult(response);
}

public Task<SearchItemsResponse> searchItemsAsync(SearchItemsRequest request) {
PlayFabEconomyAPI.SearchItems(request, OnSearchItemsRequestComplete, error => Debug.LogError(error.GenerateErrorReport()));
return searchItemsAsyncTaskSource.Task;
}
}

public class PurchaseJsonData
{
public string orderId;
public string packageName;
public string productId;
public long purchaseTime;
public int purchaseState;
public string purchaseToken;
}

public class PurchasePayloadData
{
public PurchaseJsonData JsonData;

public string signature;
public string json;

public static PurchasePayloadData FromJson(string json)
{
var payload = JsonUtility.FromJson<PurchasePayloadData>(json);
payload.JsonData = JsonUtility.FromJson<PurchaseJsonData>(json);
return payload;
}
}

public class GooglePurchase
{
public PurchasePayloadData PayloadData;

public string Store;
public string TransactionID;
public string Payload;

public static GooglePurchase FromJson(string json)
{
var purchase = JsonUtility.FromJson<GooglePurchase>(json);
purchase.PayloadData = PurchasePayloadData.FromJson(purchase.Payload);
return purchase;
}
}
11 changes: 11 additions & 0 deletions Samples/Unity/PlayFabEconomyV2/Assets/AndroidIAPExample.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit a1cd11a

Please sign in to comment.