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(); 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); } }