440 lines
14 KiB
C#
440 lines
14 KiB
C#
![]() |
using System.Collections;
|
|||
|
using System.Reflection;
|
|||
|
using System.Threading.Tasks;
|
|||
|
using UnityEngine;
|
|||
|
using Reown.AppKit.Unity;
|
|||
|
using Reown.AppKit.Unity.Model;
|
|||
|
using System;
|
|||
|
using UnityEngine.SceneManagement;
|
|||
|
|
|||
|
[DefaultExecutionOrder(1000)]
|
|||
|
public class AppKitMetadataInjector : MonoBehaviour
|
|||
|
{
|
|||
|
[Header("WalletConnect Cloud Project ID")]
|
|||
|
[SerializeField] private string projectId = "0b840bb98f4fea8ce4647bc0b0de86a0";
|
|||
|
|
|||
|
[Header("Branding")]
|
|||
|
[SerializeField] private string appName = "BR Game";
|
|||
|
[SerializeField] private string appDescription = "Public PC build (QR connect via phone)";
|
|||
|
[SerializeField] private string appUrl = "https://example.com";
|
|||
|
[SerializeField] private string appIconUrl = "https://walletconnect.com/meta/favicon.ico";
|
|||
|
|
|||
|
[Header("Chains (first one becomes default)")]
|
|||
|
[SerializeField] private bool useEthereum = true; // eip155:1
|
|||
|
[SerializeField] private bool usePolygon = true; // eip155:137
|
|||
|
[SerializeField] private bool useBase = true; // eip155:8453
|
|||
|
|
|||
|
private bool _initialized;
|
|||
|
private string _defaultChainId = "eip155:1";
|
|||
|
|
|||
|
private IEnumerator Start()
|
|||
|
{
|
|||
|
|
|||
|
// Wait until the prefab set AppKit.Instance
|
|||
|
while (AppKit.Instance == null) yield return null;
|
|||
|
|
|||
|
// Build metadata + config
|
|||
|
var md = new Metadata(appName, appDescription, appUrl, appIconUrl);
|
|||
|
var cfg = new AppKitConfig(projectId, md)
|
|||
|
{
|
|||
|
enableEmail = false,
|
|||
|
enableOnramp = false,
|
|||
|
enableCoinbaseWallet = false,
|
|||
|
connectViewWalletsCountDesktop = 2,
|
|||
|
connectViewWalletsCountMobile = 3,
|
|||
|
};
|
|||
|
|
|||
|
// Build supported chains list (order matters: first = default)
|
|||
|
EnableDesktopWallets(cfg);
|
|||
|
var chains = new System.Collections.Generic.List<Chain>();
|
|||
|
if (useEthereum) chains.Add(ChainConstants.Chains.Ethereum);
|
|||
|
if (usePolygon) chains.Add(ChainConstants.Chains.Polygon);
|
|||
|
if (useBase) chains.Add(ChainConstants.Chains.Base);
|
|||
|
if (chains.Count == 0) chains.Add(ChainConstants.Chains.Ethereum);
|
|||
|
|
|||
|
cfg.supportedChains = chains.ToArray();
|
|||
|
_defaultChainId = cfg.supportedChains[0].ChainId; // remember default
|
|||
|
|
|||
|
// Set AppKit.Config via private setter (reflection) BEFORE init
|
|||
|
var cfgProp = typeof(AppKit).GetProperty("Config",
|
|||
|
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
|
|||
|
cfgProp.SetValue(null, cfg);
|
|||
|
|
|||
|
// Initialize (supports InitializeAsync(cfg) / Initialize(cfg) / no-arg)
|
|||
|
yield return InitializeAppKit(cfg);
|
|||
|
|
|||
|
// Select default chain if API exists (some builds require this)
|
|||
|
var selectChain = typeof(AppKit).GetMethod("SelectChain",
|
|||
|
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
|||
|
if (selectChain != null)
|
|||
|
selectChain.Invoke(null, new object[] { _defaultChainId });
|
|||
|
|
|||
|
_initialized = true;
|
|||
|
Debug.Log($"✅ AppKit initialized. Default chain: {_defaultChainId}");
|
|||
|
AppKit.ConnectorController.AccountConnected += OnWalletConnected;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// Button hook
|
|||
|
public void OnWalletConnectButton()
|
|||
|
{
|
|||
|
if (!_initialized)
|
|||
|
{
|
|||
|
StartCoroutine(OpenAfterReady());
|
|||
|
return;
|
|||
|
}
|
|||
|
//AppKit.OpenModal(ViewType.Connect); // shows QR
|
|||
|
//AppKit.ConnectorController.AccountConnected += OnWalletConnected;
|
|||
|
OpenQrModal();
|
|||
|
}
|
|||
|
public void OnBrowserExtensionButton()
|
|||
|
{
|
|||
|
if (!_initialized)
|
|||
|
{
|
|||
|
StartCoroutine(ConnectDesktopAfterReady());
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
TriggerDesktopConnect();
|
|||
|
}
|
|||
|
|
|||
|
// Waits until initialized; doesn't re-init
|
|||
|
private IEnumerator OpenAfterReady()
|
|||
|
{
|
|||
|
yield return WaitForInitialization();
|
|||
|
OpenQrModal();
|
|||
|
}
|
|||
|
|
|||
|
private IEnumerator ConnectDesktopAfterReady()
|
|||
|
{
|
|||
|
yield return WaitForInitialization();
|
|||
|
TriggerDesktopConnect();
|
|||
|
}
|
|||
|
|
|||
|
private IEnumerator WaitForInitialization()
|
|||
|
{
|
|||
|
var isInitProp = typeof(AppKit).GetProperty("IsInitialized",
|
|||
|
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
|
|||
|
|
|||
|
while (isInitProp != null && !(bool)isInitProp.GetValue(null))
|
|||
|
yield return null;
|
|||
|
yield break;
|
|||
|
}
|
|||
|
|
|||
|
private void OpenQrModal()
|
|||
|
{
|
|||
|
AppKit.OpenModal(ViewType.Connect);
|
|||
|
AppKit.ConnectorController.AccountConnected += OnWalletConnected;
|
|||
|
}
|
|||
|
|
|||
|
private void TriggerDesktopConnect()
|
|||
|
{
|
|||
|
var controller = AppKit.ConnectorController;
|
|||
|
if (controller == null)
|
|||
|
{
|
|||
|
Debug.LogWarning("AppKit ConnectorController unavailable for desktop connection.");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
var controllerType = controller.GetType();
|
|||
|
var methods = controllerType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
|||
|
|
|||
|
foreach (var method in methods)
|
|||
|
{
|
|||
|
if (method.Name != "ConnectAsync") continue;
|
|||
|
|
|||
|
var parameters = method.GetParameters();
|
|||
|
if (parameters.Length == 0) continue;
|
|||
|
|
|||
|
var args = new object[parameters.Length];
|
|||
|
var success = true;
|
|||
|
|
|||
|
for (int i = 0; i < parameters.Length; i++)
|
|||
|
{
|
|||
|
var paramType = parameters[i].ParameterType;
|
|||
|
|
|||
|
if (paramType.IsEnum && paramType.Name.Contains("ConnectMethod"))
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
args[i] = Enum.Parse(paramType, "Desktop", true);
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
success = false;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (paramType.Name.Contains("ConnectParams"))
|
|||
|
{
|
|||
|
args[i] = Activator.CreateInstance(paramType);
|
|||
|
}
|
|||
|
else if (paramType.FullName == typeof(System.Threading.CancellationToken).FullName)
|
|||
|
{
|
|||
|
args[i] = default(System.Threading.CancellationToken);
|
|||
|
}
|
|||
|
else if (paramType.IsValueType)
|
|||
|
{
|
|||
|
args[i] = Activator.CreateInstance(paramType);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
args[i] = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!success) continue;
|
|||
|
|
|||
|
var result = method.Invoke(controller, args);
|
|||
|
if (result is Task task)
|
|||
|
{
|
|||
|
StartCoroutine(WaitForTask(task));
|
|||
|
}
|
|||
|
|
|||
|
AppKit.ConnectorController.AccountConnected += OnWalletConnected;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
Debug.LogWarning("Unable to locate desktop ConnectAsync overload; falling back to QR modal.");
|
|||
|
OpenQrModal();
|
|||
|
}
|
|||
|
|
|||
|
private IEnumerator WaitForTask(Task task)
|
|||
|
{
|
|||
|
while (task != null && !task.IsCompleted)
|
|||
|
yield return null;
|
|||
|
|
|||
|
yield break;
|
|||
|
}
|
|||
|
|
|||
|
private IEnumerator InitializeAppKit(AppKitConfig cfg)
|
|||
|
{
|
|||
|
var isInitProp = typeof(AppKit).GetProperty("IsInitialized",
|
|||
|
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
|
|||
|
if (isInitProp != null && (bool)isInitProp.GetValue(null)) yield break;
|
|||
|
|
|||
|
var flags = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public;
|
|||
|
|
|||
|
var initAsync = typeof(AppKit).GetMethod("InitializeAsync", flags);
|
|||
|
if (initAsync != null)
|
|||
|
{
|
|||
|
var ps = initAsync.GetParameters();
|
|||
|
var result = ps.Length == 1
|
|||
|
? initAsync.Invoke(null, new object[] { cfg })
|
|||
|
: initAsync.Invoke(null, null);
|
|||
|
|
|||
|
if (result is Task t)
|
|||
|
while (!t.IsCompleted) yield return null;
|
|||
|
|
|||
|
yield break;
|
|||
|
}
|
|||
|
|
|||
|
var init = typeof(AppKit).GetMethod("Initialize", flags);
|
|||
|
if (init != null)
|
|||
|
{
|
|||
|
var ps = init.GetParameters();
|
|||
|
var result = ps.Length == 1
|
|||
|
? init.Invoke(null, new object[] { cfg })
|
|||
|
: init.Invoke(null, null);
|
|||
|
|
|||
|
if (result is Task t)
|
|||
|
while (!t.IsCompleted) yield return null;
|
|||
|
|
|||
|
yield break;
|
|||
|
}
|
|||
|
|
|||
|
// If neither exists, rely on prefab auto-init
|
|||
|
yield return null;
|
|||
|
}
|
|||
|
|
|||
|
private void OnWalletConnected(object sender, Reown.AppKit.Unity.Connector.AccountConnectedEventArgs e)
|
|||
|
{
|
|||
|
Debug.Log("✅ Wallet connected!");
|
|||
|
Debug.Log($"Address: {e.Account.Address}");
|
|||
|
PlayerPrefs.SetString("WALLET_ADDRESS", e.Account.Address);
|
|||
|
PlayerLoginOrSignup();
|
|||
|
SceneManager.LoadScene(1);
|
|||
|
|
|||
|
}
|
|||
|
private void EnableDesktopWallets(AppKitConfig cfg)
|
|||
|
{
|
|||
|
TrySetConfigBoolean(cfg, "enableEIP6963", true);
|
|||
|
TrySetConfigBoolean(cfg, "enableInjected", true);
|
|||
|
TrySetConfigBoolean(cfg, "enableDesktop", true);
|
|||
|
TrySetConfigBoolean(cfg, "enableDesktopWallets", true);
|
|||
|
TrySetConfigBoolean(cfg, "enableInjectedWallets", true);
|
|||
|
}
|
|||
|
|
|||
|
private void TrySetConfigBoolean(AppKitConfig cfg, string memberName, bool value)
|
|||
|
{
|
|||
|
var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
|||
|
var type = cfg.GetType();
|
|||
|
|
|||
|
var prop = type.GetProperty(memberName, flags);
|
|||
|
if (prop != null && prop.CanWrite && prop.PropertyType == typeof(bool))
|
|||
|
{
|
|||
|
prop.SetValue(cfg, value);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
var field = type.GetField(memberName, flags);
|
|||
|
if (field != null && field.FieldType == typeof(bool))
|
|||
|
{
|
|||
|
field.SetValue(cfg, value);
|
|||
|
}
|
|||
|
}
|
|||
|
public async void PlayerLoginOrSignup()
|
|||
|
{
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
var rec = await GameDb.WalletConnectedAsync(PlayerPrefs.GetString("WALLET_ADDRESS"));
|
|||
|
Debug.Log($"[Runtime] ✅ Ensured player: {rec.WalletAddress} kills={rec.TotalKills} currency={rec.InGameCurrency}");
|
|||
|
}
|
|||
|
catch (System.Exception e)
|
|||
|
{
|
|||
|
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
[ContextMenu("AddKill")]
|
|||
|
public async void AddKill()
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
var rec = await GameDb.AddKillAsync(PlayerPrefs.GetString("WALLET_ADDRESS"));
|
|||
|
Debug.Log($"[Runtime] ✅ Ensured player: {rec.WalletAddress} kills={rec.TotalKills} currency={rec.InGameCurrency}");
|
|||
|
}
|
|||
|
catch (System.Exception e)
|
|||
|
{
|
|||
|
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
|||
|
}
|
|||
|
}
|
|||
|
[ContextMenu("AddCurrency")]
|
|||
|
|
|||
|
public async void AddCurrency()
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
var rec = await GameDb.AddCurrencyAsync(PlayerPrefs.GetString("WALLET_ADDRESS"),100);
|
|||
|
Debug.Log($"[Runtime] ✅ Ensured player: {rec.WalletAddress} kills={rec.TotalKills} currency={rec.InGameCurrency}");
|
|||
|
}
|
|||
|
catch (System.Exception e)
|
|||
|
{
|
|||
|
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
|||
|
}
|
|||
|
}
|
|||
|
[ContextMenu("GetCurrency")]
|
|||
|
|
|||
|
public async void GetCurrency()
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
var rec = await GameDb.GetCurrencyAsync(PlayerPrefs.GetString("WALLET_ADDRESS"));
|
|||
|
Debug.Log(rec.ToString());
|
|||
|
}
|
|||
|
catch (System.Exception e)
|
|||
|
{
|
|||
|
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
|||
|
}
|
|||
|
}
|
|||
|
[ContextMenu("GetInventory")]
|
|||
|
|
|||
|
public async void GetPurchasedItem()
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
var rec = await GameDb.GetPurchasedItemsJsonAsync(PlayerPrefs.GetString("WALLET_ADDRESS"));
|
|||
|
Debug.Log(rec.ToString());
|
|||
|
}
|
|||
|
catch (System.Exception e)
|
|||
|
{
|
|||
|
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
|||
|
}
|
|||
|
}
|
|||
|
[ContextMenu("AddGamesPlayed")]
|
|||
|
|
|||
|
public async void AddGamesPlayed()
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
var rec = await GameDb.IncGamesPlayedAsync(PlayerPrefs.GetString("WALLET_ADDRESS"));
|
|||
|
Debug.Log(rec.ToString());
|
|||
|
}
|
|||
|
catch (System.Exception e)
|
|||
|
{
|
|||
|
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
|||
|
}
|
|||
|
}
|
|||
|
[ContextMenu("GetplayerData")]
|
|||
|
|
|||
|
public async void PlayerDataAsync()
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
var rec = await GameDb.GetPlayerAsync(PlayerPrefs.GetString("WALLET_ADDRESS"));
|
|||
|
Debug.Log(rec.ToString());
|
|||
|
}
|
|||
|
catch (System.Exception e)
|
|||
|
{
|
|||
|
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
[ContextMenu("Placement")]
|
|||
|
|
|||
|
public async void PlayerPlacement()
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
var rec = await GameDb.SendGameWinAsync(PlayerPrefs.GetString("WALLET_ADDRESS"),1);
|
|||
|
Debug.Log(rec.ToString());
|
|||
|
}
|
|||
|
catch (System.Exception e)
|
|||
|
{
|
|||
|
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
[ContextMenu("ItemBought")]
|
|||
|
|
|||
|
public async void AddPurchaseItem()
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
var rec = await GameDb.AddPurchasedItemAsync(PlayerPrefs.GetString("WALLET_ADDRESS"), "ChadGuy");
|
|||
|
Debug.Log(rec.ToString());
|
|||
|
}
|
|||
|
catch (System.Exception e)
|
|||
|
{
|
|||
|
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
[ContextMenu("CheckName")]
|
|||
|
|
|||
|
public async void OnWalletConnected(string wallet) // call this from your wallet SDK
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
// makes sure the row exists (display_name = "" on first create)
|
|||
|
await GameDb.GetPlayerNameAsync(wallet);
|
|||
|
Debug.Log($"Player ensured for {wallet}");
|
|||
|
}
|
|||
|
catch (System.Exception e)
|
|||
|
{
|
|||
|
Debug.LogError(e);
|
|||
|
}
|
|||
|
}
|
|||
|
public void LoginAsGuest()
|
|||
|
{
|
|||
|
|
|||
|
SceneManager.LoadScene(1);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|