Files

394 lines
12 KiB
C#

using System;
using UnityEngine;
using UnityEngine.Purchasing;
using System.Collections;
using UnityEngine.Purchasing.Extension;
using System.Threading.Tasks;
public class IAPManager : MonoBehaviour, IDetailedStoreListener
{
private static IStoreController storeController;
private static IExtensionProvider storeExtensionProvider;
public const string PRODUCT_1000_COINS = "1000_coins";
public const string PRODUCT_2150_COINS = "2150_coins";
public const string PRODUCT_4350_COINS = "4350_coins";
public const string PRODUCT_6700_COINS = "6700_coins";
public const string PRODUCT_11500_COINS = "11500_coins";
private CoinWalletSystem coinWalletSystem;
private StoreUIManager storeUIManager;
[SerializeField] private GameObject purchaseLoadingUI;
[SerializeField] private GameObject purchaseSuccessUI;
[SerializeField] private GameObject purchaseFailedUI;
private void Start()
{
coinWalletSystem = CoinWalletSystem.Instance;
storeUIManager = FindAnyObjectByType<StoreUIManager>();
// Deactivate both UIs initially
if (storeUIManager != null) storeUIManager.gameObject.SetActive(false);
// Check if in development (Editor) or production (build)
#if UNITY_EDITOR
// In development, show fake store UI
#else
// In production, show real store UI
//if (storeUIManager != null) storeUIManager.gameObject.SetActive(true);
#endif
if (storeController == null)
{
InitializePurchasing();
}
}
private void InitializePurchasing()
{
if (IsInitialized()) return;
try
{
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
builder.AddProduct(PRODUCT_1000_COINS, ProductType.Consumable);
builder.AddProduct(PRODUCT_2150_COINS, ProductType.Consumable);
builder.AddProduct(PRODUCT_4350_COINS, ProductType.Consumable);
builder.AddProduct(PRODUCT_6700_COINS, ProductType.Consumable);
builder.AddProduct(PRODUCT_11500_COINS, ProductType.Consumable);
Debug.Log("Initializing Unity Purchasing...");
UnityPurchasing.Initialize(this, builder);
}
catch (Exception e)
{
Debug.LogError($"Error initializing IAP: {e.Message}");
}
}
private bool IsInitialized() => storeController != null && storeExtensionProvider != null;
public void Buy1000Coins() { BuyProduct(PRODUCT_1000_COINS, 1000); }
public void Buy2150Coins() { BuyProduct(PRODUCT_2150_COINS, 2150); }
public void Buy4350Coins() { BuyProduct(PRODUCT_4350_COINS, 4350); }
public void Buy6700Coins() { BuyProduct(PRODUCT_6700_COINS, 6700); }
public void Buy11500Coins() { BuyProduct(PRODUCT_11500_COINS, 11500); }
public void BuyProduct(string productID, int coinsToAdd)
{
try
{
ShowPurchaseLoading(true);
Debug.Log($"Attempting to purchase {coinsToAdd} coins");
if (coinWalletSystem == null)
{
coinWalletSystem = CoinWalletSystem.Instance;
if (coinWalletSystem == null)
{
Debug.LogError("CoinWalletSystem is not initialized!");
ShowPurchaseResult(false);
return;
}
}
// Check if in development (Editor) or production (build)
#if UNITY_EDITOR
// In development mode, simulate the purchase
Debug.Log($"Development mode: Simulating purchase of {coinsToAdd} coins");
SimulatePurchase(coinsToAdd);
#else
// In production mode, trigger the real IAP purchase flow
if (IsInitialized())
{
Product product = storeController.products.WithID(productID);
if (product != null && product.availableToPurchase)
{
storeController.InitiatePurchase(product);
}
else
{
Debug.LogError("Product not available for purchase: " + productID);
ShowPurchaseResult(false);
}
}
else
{
Debug.LogError("In-App Purchasing is not initialized.");
ShowPurchaseResult(false);
}
#endif
}
catch (System.Exception e)
{
Debug.LogError($"Error purchasing coins: {e.Message}");
ShowPurchaseResult(false);
}
finally
{
ShowPurchaseLoading(false);
}
}
// Add this new method to handle development mode purchases
private async void SimulatePurchase(int coinsToAdd)
{
if (!gameObject.activeInHierarchy)
{
gameObject.SetActive(true);
}
try
{
Debug.Log($"Simulating purchase of {coinsToAdd} coins");
ShowPurchaseLoading(true);
// Simulate a short delay to mimic network request
await Task.Delay(1000);
// Add coins directly in development mode
await coinWalletSystem.AddCoins(coinsToAdd);
// Ensure the game object is still active before showing the result
if (gameObject != null && gameObject.activeInHierarchy)
{
ShowPurchaseResult(true);
}
Debug.Log($"Development mode: Successfully added {coinsToAdd} coins");
}
catch (Exception e)
{
Debug.LogError($"Development mode: Failed to simulate purchase: {e.Message}");
if (gameObject != null && gameObject.activeInHierarchy)
{
ShowPurchaseResult(false);
}
}
finally
{
if (gameObject != null && gameObject.activeInHierarchy)
{
ShowPurchaseLoading(false);
}
}
}
// Called when a purchase completes
public void OnPurchaseComplete(Product product)
{
try
{
int coinsToAdd = 0;
// Determine the number of coins based on the product ID
if (product.definition.id == PRODUCT_1000_COINS)
{
coinsToAdd = 1000;
}
else if (product.definition.id == PRODUCT_2150_COINS)
{
coinsToAdd = 2150;
}
else if (product.definition.id == PRODUCT_4350_COINS)
{
coinsToAdd = 4350;
}
else if (product.definition.id == PRODUCT_6700_COINS)
{
coinsToAdd = 6700;
}
else if (product.definition.id == PRODUCT_11500_COINS)
{
coinsToAdd = 11500;
}
else
{
Debug.LogError("Unrecognized product ID.");
ShowPurchaseResult(false);
return;
}
// Add the coins to the wallet and show the result
if (coinWalletSystem != null)
{
coinWalletSystem.AddCoins(coinsToAdd);
ShowPurchaseResult(true); // Show success UI
}
else
{
Debug.LogError("CoinWalletSystem not found!");
ShowPurchaseResult(false); // Show failure UI
}
}
catch (Exception e)
{
Debug.LogError($"Error processing purchase: {e.Message}");
ShowPurchaseResult(false); // Show failure UI
}
}
// Called when a purchase fails
public void OnPurchaseFailed(Product product, PurchaseFailureDescription failureDescription)
{
Debug.LogError($"Purchase failed for {product.definition.id}: {failureDescription.message}");
ShowPurchaseResult(false);
}
// This method simulates showing the store UI in the development build
private void ShowFakeStore(string productID, int coinsToAdd)
{
// Show the fake store UI or simulate the purchase process
Debug.Log($"Fake store: ready to purchase {coinsToAdd} coins.");
// You may trigger the "Buy" button in the fake store UI to simulate a successful purchase
}
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
{
if (!gameObject.activeInHierarchy)
{
gameObject.SetActive(true);
}
Debug.Log($"Processing purchase for product: {args.purchasedProduct.definition.id}");
if (coinWalletSystem == null)
{
coinWalletSystem = CoinWalletSystem.Instance;
}
string productId = args.purchasedProduct.definition.id;
int coinsToAdd = 0;
switch (productId)
{
case PRODUCT_1000_COINS: coinsToAdd = 1000; break;
case PRODUCT_2150_COINS: coinsToAdd = 2150; break;
case PRODUCT_4350_COINS: coinsToAdd = 4350; break;
case PRODUCT_6700_COINS: coinsToAdd = 6700; break;
case PRODUCT_11500_COINS: coinsToAdd = 11500; break;
default:
Debug.LogError($"Unrecognized product ID {productId}");
return PurchaseProcessingResult.Complete;
}
if (coinsToAdd > 0 && coinWalletSystem != null)
{
// Use async/await pattern with Task.Run to handle the async operation
StartCoroutine(ProcessPurchaseAsync(coinsToAdd));
}
else
{
Debug.LogError("Failed to add coins: CoinWalletSystem not found or coins amount is 0");
ShowPurchaseResult(false);
}
return PurchaseProcessingResult.Complete;
}
private IEnumerator ProcessPurchaseAsync(int coinsToAdd)
{
ShowPurchaseLoading(true);
var task = coinWalletSystem.AddCoins(coinsToAdd);
while (!task.IsCompleted)
{
yield return null;
}
if (task.Exception == null)
{
ShowPurchaseResult(true);
}
else
{
Debug.LogError($"Failed to process purchase: {task.Exception}");
ShowPurchaseResult(false);
}
ShowPurchaseLoading(false);
}
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
storeController = controller;
storeExtensionProvider = extensions;
}
public void OnInitializeFailed(InitializationFailureReason error)
{
Debug.LogError($"IAP initialization failed: {error.ToString()}");
}
public void OnInitializeFailed(InitializationFailureReason error, string message)
{
Debug.LogError($"IAP initialization failed: {error.ToString()}, Message: {message}");
}
// Add the BuyProductID method here
public void BuyProductID(string productID)
{
if (IsInitialized())
{
Product product = storeController.products.WithID(productID);
if (product != null && product.availableToPurchase)
{
storeController.InitiatePurchase(product);
}
else
{
Debug.LogError("Product not available for purchase: " + productID);
}
}
else
{
Debug.LogError("In-App Purchasing is not initialized.");
}
}
private void ShowPurchaseLoading(bool show)
{
if (purchaseLoadingUI != null)
purchaseLoadingUI.SetActive(show);
}
private void ShowPurchaseResult(bool success)
{
if (!gameObject.activeInHierarchy) return;
if (success && purchaseSuccessUI != null)
{
purchaseSuccessUI.SetActive(true);
StartCoroutine(HideUI(purchaseSuccessUI, 2f));
}
else if (!success && purchaseFailedUI != null)
{
purchaseFailedUI.SetActive(true);
StartCoroutine(HideUI(purchaseFailedUI, 2f));
}
}
private IEnumerator HideUI(GameObject ui, float duration)
{
if (ui == null) yield break;
yield return new WaitForSeconds(duration);
if (ui != null && gameObject != null && gameObject.activeInHierarchy)
{
ui.SetActive(false);
}
}
public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
{
Debug.LogError($"Purchase failed - Product: {product.definition.id}, Reason: {failureReason}");
ShowPurchaseResult(false);
}
}