diff --git a/Assets/Thirdweb/Editor/ThirdwebManagerEditor.cs b/Assets/Thirdweb/Editor/ThirdwebManagerEditor.cs index b3fe1b0c7..a7cacd7c0 100644 --- a/Assets/Thirdweb/Editor/ThirdwebManagerEditor.cs +++ b/Assets/Thirdweb/Editor/ThirdwebManagerEditor.cs @@ -5,119 +5,59 @@ namespace Thirdweb.Editor { - [CustomEditor(typeof(ThirdwebManager))] - public class ThirdwebManagerEditor : UnityEditor.Editor + public abstract class ThirdwebManagerBaseEditor : UnityEditor.Editor + where T : MonoBehaviour { - private SerializedProperty clientIdProp; - private SerializedProperty bundleIdProp; - private SerializedProperty initializeOnAwakeProp; - private SerializedProperty showDebugLogsProp; - private SerializedProperty optOutUsageAnalyticsProp; - private SerializedProperty supportedChainsProp; - private SerializedProperty redirectPageHtmlOverrideProp; - - private int selectedTab = 0; - private readonly string[] tabTitles = { "Client", "Preferences", "Misc", "Debug" }; + protected SerializedProperty initializeOnAwakeProp; + protected SerializedProperty showDebugLogsProp; + protected SerializedProperty autoConnectLastWalletProp; + protected SerializedProperty supportedChainsProp; + protected SerializedProperty includedWalletIdsProp; + protected SerializedProperty redirectPageHtmlOverrideProp; + protected SerializedProperty rpcOverridesProp; - private GUIStyle headerStyle; - private GUIStyle buttonStyle; + protected int selectedTab; + protected GUIStyle buttonStyle; + protected Texture2D bannerImage; - private Texture2D bannerImage; + protected virtual string[] TabTitles => new string[] { "Client/Server", "Preferences", "Misc", "Debug" }; - private void OnEnable() + protected virtual void OnEnable() { - clientIdProp = FindProperty("ClientId"); - bundleIdProp = FindProperty("BundleId"); - initializeOnAwakeProp = FindProperty("InitializeOnAwake"); - showDebugLogsProp = FindProperty("ShowDebugLogs"); - optOutUsageAnalyticsProp = FindProperty("OptOutUsageAnalytics"); - supportedChainsProp = FindProperty("SupportedChains"); - redirectPageHtmlOverrideProp = FindProperty("RedirectPageHtmlOverride"); + initializeOnAwakeProp = FindProp("InitializeOnAwake"); + showDebugLogsProp = FindProp("ShowDebugLogs"); + autoConnectLastWalletProp = FindProp("AutoConnectLastWallet"); + supportedChainsProp = FindProp("SupportedChains"); + includedWalletIdsProp = FindProp("IncludedWalletIds"); + redirectPageHtmlOverrideProp = FindProp("RedirectPageHtmlOverride"); + rpcOverridesProp = FindProp("RpcOverrides"); bannerImage = Resources.Load("EditorBanner"); } - private void InitializeStyles() - { - buttonStyle = new GUIStyle(GUI.skin.button) - { - fontStyle = FontStyle.Bold, - alignment = TextAnchor.MiddleLeft, - padding = new RectOffset(10, 10, 10, 10) - }; - } - - private SerializedProperty FindProperty(string propertyName) - { - var targetType = target.GetType(); - var property = targetType.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); - if (property == null) - return null; - - var backingFieldName = $"<{propertyName}>k__BackingField"; - return serializedObject.FindProperty(backingFieldName); - } - public override void OnInspectorGUI() { serializedObject.Update(); - if (headerStyle == null || buttonStyle == null) + if (buttonStyle == null) { InitializeStyles(); } - // Draw Banner and Title DrawBannerAndTitle(); - - // Draw Tab Bar DrawTabs(); - - // Draw Selected Tab Content GUILayout.Space(10); DrawSelectedTabContent(); serializedObject.ApplyModifiedProperties(); } - private void DrawBannerAndTitle() - { - GUILayout.BeginVertical(); - GUILayout.Space(10); - - GUILayout.BeginHorizontal(); - - if (bannerImage != null) - { - GUILayout.Label(bannerImage, GUILayout.Width(64), GUILayout.Height(64)); - } - - GUILayout.Space(10); - - GUILayout.BeginVertical(); - GUILayout.Space(10); - GUILayout.Label("Thirdweb Configuration", EditorStyles.boldLabel); - GUILayout.Label("Configure your settings and preferences.\nYou can access ThirdwebManager.Instance from anywhere.", EditorStyles.miniLabel); - GUILayout.EndVertical(); - - GUILayout.EndHorizontal(); - - GUILayout.Space(10); - - GUILayout.EndVertical(); - } - - private void DrawTabs() - { - selectedTab = GUILayout.Toolbar(selectedTab, tabTitles, GUILayout.Height(25)); - } - - private void DrawSelectedTabContent() + protected virtual void DrawSelectedTabContent() { switch (selectedTab) { case 0: - DrawClientTab(); + DrawClientOrServerTab(); break; case 1: DrawPreferencesTab(); @@ -134,62 +74,54 @@ private void DrawSelectedTabContent() } } - private void DrawClientTab() - { - EditorGUILayout.HelpBox("Configure your client settings here.", MessageType.Info); - DrawProperty(clientIdProp, "Client ID"); - DrawProperty(bundleIdProp, "Bundle ID"); - DrawButton( - "Create API Key", - () => - { - Application.OpenURL("https://thirdweb.com/create-api-key"); - } - ); - } + protected abstract void DrawClientOrServerTab(); - private void DrawPreferencesTab() + protected virtual void DrawPreferencesTab() { EditorGUILayout.HelpBox("Set your preferences and initialization options here.", MessageType.Info); DrawProperty(initializeOnAwakeProp, "Initialize On Awake"); DrawProperty(showDebugLogsProp, "Show Debug Logs"); - DrawProperty(optOutUsageAnalyticsProp, "Opt-Out of Usage Analytics"); + DrawProperty(autoConnectLastWalletProp, "Auto-Connect Last Wallet"); } - private void DrawMiscTab() + protected virtual void DrawMiscTab() { EditorGUILayout.HelpBox("Configure other settings here.", MessageType.Info); - - // Wallet Connect Settings - GUILayout.Label("Wallet Connect Settings", EditorStyles.boldLabel); - DrawProperty(supportedChainsProp, "Supported Chains"); - + DrawProperty(rpcOverridesProp, "RPC Overrides"); GUILayout.Space(10); - - // Desktop OAuth Settings - GUILayout.Label("Desktop OAuth Settings", EditorStyles.boldLabel); - EditorGUILayout.LabelField("Redirect Page HTML Override", EditorStyles.boldLabel); + EditorGUILayout.LabelField("OAuth Redirect Page HTML Override", EditorStyles.boldLabel); redirectPageHtmlOverrideProp.stringValue = EditorGUILayout.TextArea(redirectPageHtmlOverrideProp.stringValue, GUILayout.MinHeight(75)); + GUILayout.Space(10); + DrawProperty(supportedChainsProp, "WalletConnect Supported Chains"); + DrawProperty(includedWalletIdsProp, "WalletConnect Included Wallet IDs"); } - private void DrawDebugTab() + protected virtual void DrawDebugTab() { EditorGUILayout.HelpBox("Debug your settings here.", MessageType.Info); - DrawButton( "Log Active Wallet Info", () => { if (Application.isPlaying) { - var wallet = ((ThirdwebManager)target).GetActiveWallet(); - if (wallet != null) + var mgr = target as T; + var method = mgr.GetType().GetMethod("GetActiveWallet", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (method != null) { - Debug.Log($"Active Wallet ({wallet.GetType().Name}) Address: {wallet.GetAddress().Result}"); + var wallet = method.Invoke(mgr, null) as IThirdwebWallet; + if (wallet != null) + { + Debug.Log($"Active Wallet ({wallet.GetType().Name}) Address: {wallet.GetAddress().Result}"); + } + else + { + Debug.LogWarning("No active wallet found."); + } } else { - Debug.LogWarning("No active wallet found."); + Debug.LogWarning("GetActiveWallet() not found."); } } else @@ -198,7 +130,6 @@ private void DrawDebugTab() } } ); - DrawButton( "Open Documentation", () => @@ -208,7 +139,42 @@ private void DrawDebugTab() ); } - private void DrawProperty(SerializedProperty property, string label) + protected void DrawBannerAndTitle() + { + GUILayout.BeginVertical(); + GUILayout.Space(10); + GUILayout.BeginHorizontal(); + if (bannerImage != null) + { + GUILayout.Label(bannerImage, GUILayout.Width(64), GUILayout.Height(64)); + } + GUILayout.Space(10); + GUILayout.BeginVertical(); + GUILayout.Space(10); + GUILayout.Label("Thirdweb Configuration", EditorStyles.boldLabel); + GUILayout.Label("Configure your settings and preferences.\nYou can access ThirdwebManager.Instance from anywhere.", EditorStyles.miniLabel); + GUILayout.EndVertical(); + GUILayout.EndHorizontal(); + GUILayout.Space(10); + GUILayout.EndVertical(); + } + + protected void DrawTabs() + { + selectedTab = GUILayout.Toolbar(selectedTab, TabTitles, GUILayout.Height(25)); + } + + protected void InitializeStyles() + { + buttonStyle = new GUIStyle(GUI.skin.button) + { + fontStyle = FontStyle.Bold, + alignment = TextAnchor.MiddleLeft, + padding = new RectOffset(10, 10, 10, 10) + }; + } + + protected void DrawProperty(SerializedProperty property, string label) { if (property != null) { @@ -220,15 +186,81 @@ private void DrawProperty(SerializedProperty property, string label) } } - private void DrawButton(string label, System.Action action) + protected void DrawButton(string label, System.Action action) { GUILayout.FlexibleSpace(); - // center label if (GUILayout.Button(label, buttonStyle, GUILayout.Height(35), GUILayout.ExpandWidth(true))) { action.Invoke(); } GUILayout.FlexibleSpace(); } + + protected SerializedProperty FindProp(string propName) + { + var targetType = target.GetType(); + var property = targetType.GetProperty(propName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + if (property == null) + return null; + var backingFieldName = $"<{propName}>k__BackingField"; + return serializedObject.FindProperty(backingFieldName); + } + } + + [CustomEditor(typeof(ThirdwebManager))] + public class ThirdwebManagerEditor : ThirdwebManagerBaseEditor + { + SerializedProperty clientIdProp; + SerializedProperty bundleIdProp; + + protected override void OnEnable() + { + base.OnEnable(); + clientIdProp = FindProp("ClientId"); + bundleIdProp = FindProp("BundleId"); + } + + protected override string[] TabTitles => new string[] { "Client", "Preferences", "Misc", "Debug" }; + + protected override void DrawClientOrServerTab() + { + EditorGUILayout.HelpBox("Configure your client settings here.", MessageType.Info); + DrawProperty(clientIdProp, "Client ID"); + DrawProperty(bundleIdProp, "Bundle ID"); + DrawButton( + "Create API Key", + () => + { + Application.OpenURL("https://thirdweb.com/create-api-key"); + } + ); + } + } + + [CustomEditor(typeof(ThirdwebManagerServer))] + public class ThirdwebManagerServerEditor : ThirdwebManagerBaseEditor + { + SerializedProperty secretKeyProp; + + protected override void OnEnable() + { + base.OnEnable(); + secretKeyProp = FindProp("SecretKey"); + } + + protected override string[] TabTitles => new string[] { "Client", "Preferences", "Misc", "Debug" }; + + protected override void DrawClientOrServerTab() + { + EditorGUILayout.HelpBox("Configure your client settings here.", MessageType.Info); + DrawProperty(secretKeyProp, "Secret Key"); + DrawButton( + "Create API Key", + () => + { + Application.OpenURL("https://thirdweb.com/create-api-key"); + } + ); + } } } diff --git a/Assets/Thirdweb/Examples/Scenes/Scene_Playground.unity b/Assets/Thirdweb/Examples/Scenes/Scene_Playground.unity index 5603b4624..a322cd379 100644 --- a/Assets/Thirdweb/Examples/Scenes/Scene_Playground.unity +++ b/Assets/Thirdweb/Examples/Scenes/Scene_Playground.unity @@ -13,7 +13,7 @@ OcclusionCullingSettings: --- !u!104 &2 RenderSettings: m_ObjectHideFlags: 0 - serializedVersion: 10 + serializedVersion: 9 m_Fog: 0 m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} m_FogMode: 3 @@ -43,6 +43,7 @@ RenderSettings: LightmapSettings: m_ObjectHideFlags: 0 serializedVersion: 12 + m_GIWorkflowMode: 1 m_GISettings: serializedVersion: 2 m_BounceScale: 1 @@ -65,6 +66,9 @@ LightmapSettings: m_LightmapParameters: {fileID: 0} m_LightmapsBakeMode: 1 m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 m_ReflectionCompression: 2 m_MixedBakeMode: 2 m_BakeBackend: 1 @@ -339,17 +343,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -596,17 +598,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -732,17 +732,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 3 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 1 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -923,17 +921,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -1456,17 +1452,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -1626,13 +1620,10 @@ MonoBehaviour: m_GlobalFontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} m_OnFocusSelectAll: 1 m_ResetOnDeActivation: 1 - m_KeepTextSelectionVisible: 0 m_RestoreOriginalTextOnEscape: 1 m_isRichTextEditingAllowed: 0 m_LineLimit: 0 - isAlert: 0 m_InputValidator: {fileID: 0} - m_ShouldActivateOnSelect: 1 --- !u!114 &187539453 MonoBehaviour: m_ObjectHideFlags: 0 @@ -1784,17 +1775,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 1 + m_enableWordWrapping: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -1920,17 +1909,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -2110,10 +2097,10 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 36 + m_fontSize: 31.45 m_fontSizeBase: 36 m_fontWeight: 400 - m_enableAutoSizing: 0 + m_enableAutoSizing: 1 m_fontSizeMin: 18 m_fontSizeMax: 72 m_fontStyle: 0 @@ -2126,17 +2113,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 1 + m_enableWordWrapping: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -2383,17 +2368,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -2571,17 +2554,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -2828,17 +2809,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -3105,17 +3084,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -3241,17 +3218,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -3377,17 +3352,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -3689,17 +3662,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -4067,17 +4038,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -4203,17 +4172,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -4524,17 +4491,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -4859,17 +4824,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 1 + m_enableWordWrapping: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -4995,17 +4958,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 1 + m_enableWordWrapping: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -5252,17 +5213,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -5388,17 +5347,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -5587,17 +5544,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -5744,17 +5699,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 1 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -6083,17 +6036,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -6461,17 +6412,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -6597,17 +6546,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -6733,17 +6680,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 3 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 1 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -7125,17 +7070,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -7261,17 +7204,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -7518,17 +7459,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 1 + m_enableWordWrapping: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -7706,17 +7645,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -7842,17 +7779,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -7978,17 +7913,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -8114,17 +8047,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -8250,17 +8181,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -8386,17 +8315,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -8522,17 +8449,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 1 + m_enableWordWrapping: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -8692,13 +8617,10 @@ MonoBehaviour: m_GlobalFontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} m_OnFocusSelectAll: 1 m_ResetOnDeActivation: 1 - m_KeepTextSelectionVisible: 0 m_RestoreOriginalTextOnEscape: 1 m_isRichTextEditingAllowed: 0 m_LineLimit: 0 - isAlert: 0 m_InputValidator: {fileID: 0} - m_ShouldActivateOnSelect: 1 --- !u!114 &1047630456 MonoBehaviour: m_ObjectHideFlags: 0 @@ -8850,17 +8772,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -9128,17 +9048,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 1 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -9264,17 +9182,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -9400,17 +9316,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -9657,17 +9571,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 1 + m_enableWordWrapping: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -9914,17 +9826,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -10217,17 +10127,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -10353,17 +10261,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -10552,17 +10458,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -10809,17 +10713,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -11308,17 +11210,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -11761,17 +11661,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -11897,17 +11795,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -12047,17 +11943,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -12183,17 +12077,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -12319,17 +12211,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -12455,17 +12345,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -12726,17 +12614,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -13075,17 +12961,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -13211,17 +13095,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -13424,17 +13306,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -13802,17 +13682,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -13992,17 +13870,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -14370,17 +14246,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -14520,17 +14394,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -14670,17 +14542,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -14809,17 +14679,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -15640,17 +15508,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 1 + m_enableWordWrapping: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -15911,17 +15777,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -16047,17 +15911,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -16183,17 +16045,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 1 + m_enableWordWrapping: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -16319,17 +16179,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -16702,17 +16560,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -16838,17 +16694,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -16974,17 +16828,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -17173,17 +17025,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 1 + m_enableWordWrapping: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -17547,17 +17397,15 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_TextWrappingMode: 0 + m_enableWordWrapping: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 - m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 - m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 diff --git a/Assets/Thirdweb/Examples/Scripts/PlaygroundManager.cs b/Assets/Thirdweb/Examples/Scripts/PlaygroundManager.cs index 0bec43e7a..e55bb617f 100644 --- a/Assets/Thirdweb/Examples/Scripts/PlaygroundManager.cs +++ b/Assets/Thirdweb/Examples/Scripts/PlaygroundManager.cs @@ -125,6 +125,7 @@ private async void ConnectWallet(WalletOptions options) currentPanel.Action1Button.onClick.AddListener(async () => { var address = await wallet.GetAddress(); + address.CopyToClipboard(); Log(currentPanel.LogText, $"Address: {address}"); }); @@ -415,10 +416,6 @@ private async void InitializeAccountAbstractionPanel() { try { - if (!await smartWallet.IsDeployed()) - { - Log(panel.LogText, "Account not deployed yet, deploying before signing..."); - } var message = "Hello, World!"; var signature = await smartWallet.PersonalSign(message); Log(panel.LogText, $"Signature: {signature}"); diff --git a/Assets/Thirdweb/Plugins/ThreadingPatcher/Editor/WebGLThreadingPatcher.cs b/Assets/Thirdweb/Plugins/ThreadingPatcher/Editor/WebGLThreadingPatcher.cs index 037451444..d6f6dbee9 100644 --- a/Assets/Thirdweb/Plugins/ThreadingPatcher/Editor/WebGLThreadingPatcher.cs +++ b/Assets/Thirdweb/Plugins/ThreadingPatcher/Editor/WebGLThreadingPatcher.cs @@ -18,7 +18,11 @@ public void OnPostBuildPlayerScriptDLLs(BuildReport report) if (report.summary.platform != BuildTarget.WebGL) return; +#if UNITY_2022_1_OR_NEWER var mscorLibDll = report.GetFiles().FirstOrDefault(f => f.path.EndsWith("mscorlib.dll")).path; +#else + var mscorLibDll = report.files.FirstOrDefault(f => f.path.EndsWith("mscorlib.dll")).path; +#endif if (mscorLibDll == null) { Debug.LogError("Can't find mscorlib.dll in build dll files"); diff --git a/Assets/Thirdweb/Plugins/ThreadingPatcher/Plugins/SystemThreadingTimer.jslib b/Assets/Thirdweb/Plugins/ThreadingPatcher/Plugins/SystemThreadingTimer.jslib index 5c75db8ab..af011ec87 100644 --- a/Assets/Thirdweb/Plugins/ThreadingPatcher/Plugins/SystemThreadingTimer.jslib +++ b/Assets/Thirdweb/Plugins/ThreadingPatcher/Plugins/SystemThreadingTimer.jslib @@ -15,7 +15,7 @@ var SystemThreadingTimerLib = { setTimeout(function() { if (id === vars.currentCallbackId) - Runtime.dynCall('v', vars.callback); + {{{ makeDynCall("v", "vars.callback") }}}(); }, interval); } diff --git a/Assets/Thirdweb/Plugins/WalletConnectUnity/com.walletconnect.core/Plugins/iOS/CanOpenUrl.m b/Assets/Thirdweb/Plugins/WalletConnectUnity/com.walletconnect.core/Plugins/iOS/CanOpenUrl.m index 95d6ee787..618b35e6a 100644 --- a/Assets/Thirdweb/Plugins/WalletConnectUnity/com.walletconnect.core/Plugins/iOS/CanOpenUrl.m +++ b/Assets/Thirdweb/Plugins/WalletConnectUnity/com.walletconnect.core/Plugins/iOS/CanOpenUrl.m @@ -1,10 +1,10 @@ #import #import -NSString *ToNSString(char* string) { +NSString *ConvertCStringToNSString(char* string) { return [NSString stringWithUTF8String:string]; } bool _CanOpenURL (char* url) { - return [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:ToNSString(url)]]; + return [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:ConvertCStringToNSString(url)]]; } diff --git a/Assets/Thirdweb/Plugins/WalletConnectUnity/com.walletconnect.core/Runtime/External/NativeWebSocket/WebSocket.jslib b/Assets/Thirdweb/Plugins/WalletConnectUnity/com.walletconnect.core/Runtime/External/NativeWebSocket/WebSocket.jslib index 052f2132d..4fbe45872 100644 --- a/Assets/Thirdweb/Plugins/WalletConnectUnity/com.walletconnect.core/Runtime/External/NativeWebSocket/WebSocket.jslib +++ b/Assets/Thirdweb/Plugins/WalletConnectUnity/com.walletconnect.core/Runtime/External/NativeWebSocket/WebSocket.jslib @@ -150,7 +150,7 @@ var LibraryWebSocket = { console.log("[JSLIB WebSocket] Connected."); if (webSocketState.onOpen) - Module.dynCall_vi(webSocketState.onOpen, instanceId); + {{{ makeDynCall("vi", "webSocketState.onOpen") }}}(instanceId); }; @@ -170,7 +170,7 @@ var LibraryWebSocket = { HEAPU8.set(dataBuffer, buffer); try { - Module.dynCall_viii(webSocketState.onMessage, instanceId, buffer, dataBuffer.length); + {{{ makeDynCall("viii", "webSocketState.onMessage") }}}(instanceId, buffer, dataBuffer.length); } finally { _free(buffer); } @@ -182,7 +182,7 @@ var LibraryWebSocket = { HEAPU8.set(dataBuffer, buffer); try { - Module.dynCall_viii(webSocketState.onMessage, instanceId, buffer, dataBuffer.length); + {{{ makeDynCall("viii", "webSocketState.onMessage") }}}(instanceId, buffer, dataBuffer.length); } finally { _free(buffer); } @@ -204,7 +204,7 @@ var LibraryWebSocket = { stringToUTF8(msg, buffer, length); try { - Module.dynCall_vii(webSocketState.onError, instanceId, buffer); + {{{ makeDynCall("vii", "webSocketState.onError") }}}(instanceId, buffer); } finally { _free(buffer); } @@ -219,7 +219,7 @@ var LibraryWebSocket = { console.log("[JSLIB WebSocket] Closed."); if (webSocketState.onClose) - Module.dynCall_vii(webSocketState.onClose, instanceId, ev.code); + {{{ makeDynCall("vii", "webSocketState.onClose") }}}(instanceId, ev.code); delete instance.ws; diff --git a/Assets/Thirdweb/Plugins/WalletConnectUnity/com.walletconnect.core/Runtime/WalletConnect.cs b/Assets/Thirdweb/Plugins/WalletConnectUnity/com.walletconnect.core/Runtime/WalletConnect.cs index bdcb5f7f9..28e30ddff 100644 --- a/Assets/Thirdweb/Plugins/WalletConnectUnity/com.walletconnect.core/Runtime/WalletConnect.cs +++ b/Assets/Thirdweb/Plugins/WalletConnectUnity/com.walletconnect.core/Runtime/WalletConnect.cs @@ -99,7 +99,8 @@ public async Task InitializeAsync() Storage = storage, RelayUrl = projectConfig.RelayUrl, RelayUrlBuilder = new UnityRelayUrlBuilder(), - ConnectionBuilder = new NativeWebSocketConnectionBuilder() + ConnectionBuilder = new NativeWebSocketConnectionBuilder(), + ConnectionTimeout = TimeSpan.FromSeconds(180) } ); diff --git a/Assets/Thirdweb/Plugins/WebGLInputCopy/WebGLInput/Mobile/WebGLInputMobile.jslib b/Assets/Thirdweb/Plugins/WebGLInputCopy/WebGLInput/Mobile/WebGLInputMobile.jslib index c3fc6192d..8fdfde3dc 100644 --- a/Assets/Thirdweb/Plugins/WebGLInputCopy/WebGLInput/Mobile/WebGLInputMobile.jslib +++ b/Assets/Thirdweb/Plugins/WebGLInputCopy/WebGLInput/Mobile/WebGLInputMobile.jslib @@ -6,7 +6,7 @@ var WebGLInputMobile = { document.body.addEventListener("touchend", function () { document.body.removeEventListener("touchend", arguments.callee); - Runtime.dynCall("vi", touchend, [id]); + {{{ makeDynCall("vi", "touchend") }}}(id); }); return id; @@ -14,7 +14,7 @@ var WebGLInputMobile = { WebGLInputMobileOnFocusOut: function (id, focusout) { document.body.addEventListener("focusout", function () { document.body.removeEventListener("focusout", arguments.callee); - Runtime.dynCall("vi", focusout, [id]); + {{{ makeDynCall("vi", "focusout") }}}(id); }); }, } diff --git a/Assets/Thirdweb/Plugins/WebGLInputCopy/WebGLInput/WebGLInput.jslib b/Assets/Thirdweb/Plugins/WebGLInputCopy/WebGLInput/WebGLInput.jslib index a17092d5a..62055cbd3 100644 --- a/Assets/Thirdweb/Plugins/WebGLInputCopy/WebGLInput/WebGLInput.jslib +++ b/Assets/Thirdweb/Plugins/WebGLInputCopy/WebGLInput/WebGLInput.jslib @@ -1,19 +1,6 @@ var WebGLInput = { $instances: [], WebGLInputInit : function() { - // use WebAssembly.Table : makeDynCall - // when enable. dynCall is undefined - if(typeof dynCall === "undefined") - { - // make Runtime.dynCall to undefined - Runtime = { dynCall : undefined } - } - else - { - // Remove the `Runtime` object from "v1.37.27: 12/24/2017" - // if Runtime not defined. create and add functon!! - if(typeof Runtime === "undefined") Runtime = { dynCall : dynCall } - } }, WebGLInputCreate: function (canvasId, x, y, width, height, fontsize, text, placeholder, isMultiLine, isPassword, isHidden, isMobile) { @@ -112,7 +99,7 @@ var WebGLInput = { input.setSelectionRange(start + 1, start + 1); input.oninput(); // call oninput to exe ValueChange function!! } else { - (!!Runtime.dynCall) ? Runtime.dynCall("vii", cb, [id, e.shiftKey ? -1 : 1]) : {{{ makeDynCall("vii", "cb") }}}(id, e.shiftKey ? -1 : 1); + {{{ makeDynCall("vii", "cb") }}}(id, e.shiftKey ? -1 : 1); } } }); @@ -124,13 +111,13 @@ var WebGLInput = { WebGLInputOnFocus: function (id, cb) { var input = instances[id]; input.onfocus = function () { - (!!Runtime.dynCall) ? Runtime.dynCall("vi", cb, [id]) : {{{ makeDynCall("vi", "cb") }}}(id); + {{{ makeDynCall("vi", "cb") }}}(id); }; }, WebGLInputOnBlur: function (id, cb) { var input = instances[id]; input.onblur = function () { - (!!Runtime.dynCall) ? Runtime.dynCall("vi", cb, [id]) : {{{ makeDynCall("vi", "cb") }}}(id); + {{{ makeDynCall("vi", "cb") }}}(id); }; }, WebGLInputIsFocus: function (id) { @@ -143,7 +130,7 @@ var WebGLInput = { var bufferSize = lengthBytesUTF8(returnStr) + 1; var buffer = _malloc(bufferSize); stringToUTF8(returnStr, buffer, bufferSize); - (!!Runtime.dynCall) ? Runtime.dynCall("vii", cb, [id, buffer]) : {{{ makeDynCall("vii", "cb") }}}(id, buffer); + {{{ makeDynCall("vii", "cb") }}}(id, buffer); }; }, WebGLInputOnEditEnd:function(id, cb){ @@ -153,7 +140,7 @@ var WebGLInput = { var bufferSize = lengthBytesUTF8(returnStr) + 1; var buffer = _malloc(bufferSize); stringToUTF8(returnStr, buffer, bufferSize); - (!!Runtime.dynCall) ? Runtime.dynCall("vii", cb, [id, buffer]) : {{{ makeDynCall("vii", "cb") }}}(id, buffer); + {{{ makeDynCall("vii", "cb") }}}(id, buffer); }; }, WebGLInputOnKeyboardEvent:function(id, cb){ @@ -167,7 +154,7 @@ var WebGLInput = { var shift = e.shiftKey ? 1 : 0; var ctrl = e.ctrlKey ? 1 : 0; var alt = e.altKey ? 1 : 0; - (!!Runtime.dynCall) ? Runtime.dynCall("viiiiiii", cb, [id, mode, key, code, shift, ctrl, alt]) : {{{ makeDynCall("viiiiiii", "cb") }}}(id, mode, key, code, shift, ctrl, alt); + {{{ makeDynCall("viiiiiii", "cb") }}}(id, mode, key, code, shift, ctrl, alt); } } input.addEventListener('keydown', function(e) { func(1, e); }); diff --git a/Assets/Thirdweb/Plugins/WebGLInputCopy/WebGLWindow/WebGLWindow.jslib b/Assets/Thirdweb/Plugins/WebGLInputCopy/WebGLWindow/WebGLWindow.jslib index 42bec9354..a81860f2b 100644 --- a/Assets/Thirdweb/Plugins/WebGLInputCopy/WebGLWindow/WebGLWindow.jslib +++ b/Assets/Thirdweb/Plugins/WebGLInputCopy/WebGLWindow/WebGLWindow.jslib @@ -1,18 +1,9 @@ +#if parseInt(EMSCRIPTEN_VERSION.split('.')[0]) < 2 || (parseInt(EMSCRIPTEN_VERSION.split('.')[0]) == 2 && parseInt(EMSCRIPTEN_VERSION.split('.')[1]) < 0) || (parseInt(EMSCRIPTEN_VERSION.split('.')[0]) == 2 && parseInt(EMSCRIPTEN_VERSION.split('.')[1]) == 0 && parseInt(EMSCRIPTEN_VERSION.split('.')[2]) < 3) +#error "ThirdWeb plugin requires building with Emscripten 2.0.3 and Unity 2021.2 or newer. Please update" +#endif + var WebGLWindow = { WebGLWindowInit : function() { - // use WebAssembly.Table : makeDynCall - // when enable. dynCall is undefined - if(typeof dynCall === "undefined") - { - // make Runtime.dynCall to undefined - Runtime = { dynCall : undefined } - } - else - { - // Remove the `Runtime` object from "v1.37.27: 12/24/2017" - // if Runtime not defined. create and add functon!! - if(typeof Runtime === "undefined") Runtime = { dynCall : dynCall } - } }, WebGLWindowGetCanvasName: function() { var elements = document.getElementsByTagName('canvas'); @@ -33,17 +24,17 @@ var WebGLWindow = { }, WebGLWindowOnFocus: function (cb) { window.addEventListener('focus', function () { - (!!Runtime.dynCall) ? Runtime.dynCall("v", cb, []) : {{{ makeDynCall("v", "cb") }}}(); + {{{ makeDynCall("v", "cb") }}}(); }); }, WebGLWindowOnBlur: function (cb) { window.addEventListener('blur', function () { - (!!Runtime.dynCall) ? Runtime.dynCall("v", cb, []) : {{{ makeDynCall("v", "cb") }}}(); + {{{ makeDynCall("v", "cb") }}}(); }); }, WebGLWindowOnResize: function(cb) { window.addEventListener('resize', function () { - (!!Runtime.dynCall) ? Runtime.dynCall("v", cb, []) : {{{ makeDynCall("v", "cb") }}}(); + {{{ makeDynCall("v", "cb") }}}(); }); }, WebGLWindowInjectFullscreen : function () { diff --git a/Assets/Thirdweb/Plugins/macOS.meta b/Assets/Thirdweb/Plugins/macOS.meta new file mode 100644 index 000000000..fffc90f14 --- /dev/null +++ b/Assets/Thirdweb/Plugins/macOS.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c6e9b5dce5f146478df9f3e2df5abe10 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Thirdweb/Plugins/macOS/MacBrowser.mm b/Assets/Thirdweb/Plugins/macOS/MacBrowser.mm new file mode 100644 index 000000000..405cf1509 --- /dev/null +++ b/Assets/Thirdweb/Plugins/macOS/MacBrowser.mm @@ -0,0 +1,106 @@ +#import +#import + +#include "../iOS/Common.h" + +typedef void (*ASWebAuthenticationSessionCompletionCallback)(void* sessionPtr, const char* callbackUrl, int errorCode, const char* errorMessage); + +@interface Thirdweb_ASWebAuthenticationSession : NSObject + +@property (readonly, nonatomic) ASWebAuthenticationSession* session; + +@end + +@implementation Thirdweb_ASWebAuthenticationSession + +- (instancetype)initWithURL:(NSURL *)URL callbackURLScheme:(nullable NSString *)callbackURLScheme completionCallback:(ASWebAuthenticationSessionCompletionCallback)completionCallback +{ + self = [super init]; + if (self) + { + _session = [[ASWebAuthenticationSession alloc] initWithURL:URL + callbackURLScheme:callbackURLScheme + completionHandler:^(NSURL * _Nullable callbackURL, NSError * _Nullable error) + { + if (error != nil) + { + NSLog(@"[ASWebAuthenticationSession:CompletionHandler] %@", error.description); + } + + completionCallback((__bridge void*)self, toString(callbackURL.absoluteString), (int)error.code, toString(error.localizedDescription)); + }]; + + if (@available(macOS 10.15, *)) + { + _session.presentationContextProvider = self; + } + } + return self; +} + +- (ASPresentationAnchor)presentationAnchorForWebAuthenticationSession:(ASWebAuthenticationSession *)session +{ + if (@available(macOS 10.15, *)) + { + NSWindow* anchor = [NSApplication sharedApplication].keyWindow; + if (anchor == nil) + { + anchor = [NSApplication sharedApplication].mainWindow; + } + if (anchor == nil) + { + anchor = [NSApplication sharedApplication].windows.firstObject; + } + return anchor; + } + return nil; +} + +@end + +extern "C" +{ + Thirdweb_ASWebAuthenticationSession* Thirdweb_ASWebAuthenticationSession_InitWithURL( + const char* urlStr, const char* urlSchemeStr, ASWebAuthenticationSessionCompletionCallback completionCallback) + { + NSURL* url = [NSURL URLWithString: toString(urlStr)]; + NSString* urlScheme = toString(urlSchemeStr); + + Thirdweb_ASWebAuthenticationSession* session = [[Thirdweb_ASWebAuthenticationSession alloc] initWithURL:url + callbackURLScheme:urlScheme + completionCallback:completionCallback]; + return session; + } + + int Thirdweb_ASWebAuthenticationSession_Start(void* sessionPtr) + { + Thirdweb_ASWebAuthenticationSession* session = (__bridge Thirdweb_ASWebAuthenticationSession*) sessionPtr; + BOOL started = [[session session] start]; + return toBool(started); + } + + void Thirdweb_ASWebAuthenticationSession_Cancel(void* sessionPtr) + { + Thirdweb_ASWebAuthenticationSession* session = (__bridge Thirdweb_ASWebAuthenticationSession*) sessionPtr; + [[session session] cancel]; + } + + int Thirdweb_ASWebAuthenticationSession_GetPrefersEphemeralWebBrowserSession(void* sessionPtr) + { + Thirdweb_ASWebAuthenticationSession* session = (__bridge Thirdweb_ASWebAuthenticationSession*) sessionPtr; + if (@available(macOS 10.15, *)) + { + return toBool([[session session] prefersEphemeralWebBrowserSession]); + } + return 0; + } + + void Thirdweb_ASWebAuthenticationSession_SetPrefersEphemeralWebBrowserSession(void* sessionPtr, int enable) + { + Thirdweb_ASWebAuthenticationSession* session = (__bridge Thirdweb_ASWebAuthenticationSession*) sessionPtr; + if (@available(macOS 10.15, *)) + { + [[session session] setPrefersEphemeralWebBrowserSession:toBool(enable)]; + } + } +} diff --git a/Assets/Thirdweb/Plugins/macOS/MacBrowser.mm.meta b/Assets/Thirdweb/Plugins/macOS/MacBrowser.mm.meta new file mode 100644 index 000000000..b7cddad5a --- /dev/null +++ b/Assets/Thirdweb/Plugins/macOS/MacBrowser.mm.meta @@ -0,0 +1,84 @@ +fileFormatVersion: 2 +guid: 934bb3da36e34dfcb207b4c1d77efc9a +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 0 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Android: Android + second: + enabled: 0 + settings: + AndroidSharedLibraryType: Executable + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: AnyCPU + FrameworkDependencies: + CompileFlags: + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + iPhone: iOS + second: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Thirdweb/Plugins/macOS/README.md b/Assets/Thirdweb/Plugins/macOS/README.md new file mode 100644 index 000000000..e155fdecc --- /dev/null +++ b/Assets/Thirdweb/Plugins/macOS/README.md @@ -0,0 +1,17 @@ +# macOS OAuth Plugin + +The native bridge in this folder (`libMacBrowser.dylib`) is a universal binary (arm64 + x86_64) built from `MacBrowser.mm`. + +## Rebuild steps + +Run these commands from the repository root on macOS: + +```bash +cd Assets/Thirdweb/Plugins/macOS +clang++ -std=c++17 -ObjC++ -fmodules -Wall -Werror -arch arm64 -framework Cocoa -framework AuthenticationServices -dynamiclib MacBrowser.mm -o /tmp/libMacBrowser_arm64.dylib +clang++ -std=c++17 -ObjC++ -fmodules -Wall -Werror -arch x86_64 -framework Cocoa -framework AuthenticationServices -dynamiclib MacBrowser.mm -o /tmp/libMacBrowser_x86_64.dylib +lipo -create /tmp/libMacBrowser_arm64.dylib /tmp/libMacBrowser_x86_64.dylib -output libMacBrowser.dylib +rm /tmp/libMacBrowser_arm64.dylib /tmp/libMacBrowser_x86_64.dylib +``` + +After rebuilding, re-run your Unity macOS build to make sure the new binary is picked up. diff --git a/Assets/Thirdweb/Plugins/macOS/README.md.meta b/Assets/Thirdweb/Plugins/macOS/README.md.meta new file mode 100644 index 000000000..89019c9bd --- /dev/null +++ b/Assets/Thirdweb/Plugins/macOS/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3a9f5a8a4f5b4139af80d91a1b66ec97 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Thirdweb/Plugins/macOS/libMacBrowser.dylib b/Assets/Thirdweb/Plugins/macOS/libMacBrowser.dylib new file mode 100755 index 000000000..159733092 Binary files /dev/null and b/Assets/Thirdweb/Plugins/macOS/libMacBrowser.dylib differ diff --git a/Assets/Thirdweb/Plugins/macOS/libMacBrowser.dylib.meta b/Assets/Thirdweb/Plugins/macOS/libMacBrowser.dylib.meta new file mode 100644 index 000000000..fe0011ddd --- /dev/null +++ b/Assets/Thirdweb/Plugins/macOS/libMacBrowser.dylib.meta @@ -0,0 +1,83 @@ +fileFormatVersion: 2 +guid: d6547937dc5d4cd09d0f566cbb286ee0 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 0 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Android: Android + second: + enabled: 0 + settings: + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: OSXUniversal + second: + enabled: 1 + settings: + CPU: AnyCPU + FrameworkDependencies: AuthenticationServices; + CompileFlags: + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + iPhone: iOS + second: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Thirdweb/Runtime/NET/Thirdweb.dll b/Assets/Thirdweb/Runtime/NET/Thirdweb.dll index f5e78bbb2..8e9657979 100644 Binary files a/Assets/Thirdweb/Runtime/NET/Thirdweb.dll and b/Assets/Thirdweb/Runtime/NET/Thirdweb.dll differ diff --git a/Assets/Thirdweb/Runtime/Unity/Browser/CrossPlatformUnityBrowser.cs b/Assets/Thirdweb/Runtime/Unity/Browser/CrossPlatformUnityBrowser.cs index 58dafa8da..06b11b434 100644 --- a/Assets/Thirdweb/Runtime/Unity/Browser/CrossPlatformUnityBrowser.cs +++ b/Assets/Thirdweb/Runtime/Unity/Browser/CrossPlatformUnityBrowser.cs @@ -16,16 +16,29 @@ public CrossPlatformUnityBrowser(string htmlOverride = null) htmlOverride = null; } - var go = new GameObject("WebGLInAppWalletBrowser"); - #if UNITY_EDITOR _unityBrowser = new InAppWalletBrowser(htmlOverride); #elif UNITY_WEBGL - _unityBrowser = go.AddComponent(); +#if UNITY_6000_0_OR_NEWER + var existingBrowser = UnityEngine.Object.FindAnyObjectByType(); +#else + var existingBrowser = GameObject.FindObjectOfType(); +#endif + if (existingBrowser != null) + { + _unityBrowser = existingBrowser; + } + else + { + var go = new GameObject("WebGLInAppWalletBrowser"); + _unityBrowser = go.AddComponent(); + } #elif UNITY_ANDROID _unityBrowser = new AndroidBrowser(); #elif UNITY_IOS _unityBrowser = new IOSBrowser(); +#elif UNITY_STANDALONE_OSX + _unityBrowser = new MacBrowser(); #else _unityBrowser = new InAppWalletBrowser(htmlOverride); #endif diff --git a/Assets/Thirdweb/Runtime/Unity/Browser/iOSBrowser.cs b/Assets/Thirdweb/Runtime/Unity/Browser/iOSBrowser.cs index a3f3ba823..718f5497b 100644 --- a/Assets/Thirdweb/Runtime/Unity/Browser/iOSBrowser.cs +++ b/Assets/Thirdweb/Runtime/Unity/Browser/iOSBrowser.cs @@ -1,13 +1,12 @@ -#if UNITY_IOS && !UNITY_EDITOR +#if (UNITY_IOS || UNITY_STANDALONE_OSX) && !UNITY_EDITOR using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using AOT; -using System.Runtime.InteropServices; - namespace Thirdweb.Unity { public class ASWebAuthenticationSession : IDisposable @@ -26,7 +25,12 @@ public ASWebAuthenticationSession(string url, string callbackUrlScheme, ASWebAut { _sessionPtr = Thirdweb_ASWebAuthenticationSession_InitWithURL(url, callbackUrlScheme, OnAuthenticationSessionCompleted); - CompletionCallbacks.Add(_sessionPtr, completionHandler); + if (_sessionPtr == IntPtr.Zero) + { + throw new InvalidOperationException("Failed to initialize ASWebAuthenticationSession."); + } + + CompletionCallbacks[_sessionPtr] = completionHandler; } public bool Start() @@ -41,11 +45,18 @@ public void Cancel() public void Dispose() { - CompletionCallbacks.Remove(_sessionPtr); + if (_sessionPtr != IntPtr.Zero) + { + CompletionCallbacks.Remove(_sessionPtr); + } _sessionPtr = IntPtr.Zero; } +#if UNITY_STANDALONE_OSX + private const string DllName = "MacBrowser"; +#else private const string DllName = "__Internal"; +#endif [DllImport(DllName)] private static extern IntPtr Thirdweb_ASWebAuthenticationSession_InitWithURL(string url, string callbackUrlScheme, AuthenticationSessionCompletedCallback completionHandler); @@ -76,6 +87,7 @@ private static void OnAuthenticationSessionCompleted(IntPtr session, string call } } +#if UNITY_IOS public class IOSBrowser : IThirdwebBrowser { private TaskCompletionSource _taskCompletionSource; @@ -134,6 +146,68 @@ private void AuthenticationSessionCompletionHandler(string callbackUrl, ASWebAut } } } +#endif + +#if UNITY_STANDALONE_OSX + public class MacBrowser : IThirdwebBrowser + { + private TaskCompletionSource _taskCompletionSource; + + public bool prefersEphemeralWebBrowserSession { get; set; } = false; + + public async Task Login(ThirdwebClient client, string loginUrl, string redirectUrl, Action browserOpenAction, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(loginUrl)) + throw new ArgumentNullException(nameof(loginUrl)); + + if (string.IsNullOrEmpty(redirectUrl)) + throw new ArgumentNullException(nameof(redirectUrl)); + + _taskCompletionSource = new TaskCompletionSource(); + + redirectUrl = redirectUrl.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries)[0]; + + using var authenticationSession = new ASWebAuthenticationSession(loginUrl, redirectUrl, AuthenticationSessionCompletionHandler); + authenticationSession.prefersEphemeralWebBrowserSession = prefersEphemeralWebBrowserSession; + + cancellationToken.Register(() => + { + _taskCompletionSource?.TrySetCanceled(); + }); + + try + { + if (!authenticationSession.Start()) + { + _taskCompletionSource.SetResult(new BrowserResult(BrowserStatus.UnknownError, "Browser could not be started.")); + } + + return await _taskCompletionSource.Task; + } + catch (TaskCanceledException) + { + authenticationSession?.Cancel(); + throw; + } + } + + private void AuthenticationSessionCompletionHandler(string callbackUrl, ASWebAuthenticationSessionError error) + { + if (error.code == ASWebAuthenticationSessionErrorCode.None) + { + _taskCompletionSource.SetResult(new BrowserResult(BrowserStatus.Success, callbackUrl)); + } + else if (error.code == ASWebAuthenticationSessionErrorCode.CanceledLogin) + { + _taskCompletionSource.SetResult(new BrowserResult(BrowserStatus.UserCanceled, callbackUrl, error.message)); + } + else + { + _taskCompletionSource.SetResult(new BrowserResult(BrowserStatus.UnknownError, callbackUrl, error.message)); + } + } + } +#endif public class ASWebAuthenticationSessionError { diff --git a/Assets/Thirdweb/Runtime/Unity/Prefabs/ThirdwebManager.prefab b/Assets/Thirdweb/Runtime/Unity/Prefabs/ThirdwebManager.prefab index c18090090..8ea4a1885 100644 --- a/Assets/Thirdweb/Runtime/Unity/Prefabs/ThirdwebManager.prefab +++ b/Assets/Thirdweb/Runtime/Unity/Prefabs/ThirdwebManager.prefab @@ -52,7 +52,9 @@ MonoBehaviour: k__BackingField: 1 k__BackingField: 0 k__BackingField: ee6e060000000000 + k__BackingField: [] k__BackingField: + k__BackingField: [] --- !u!1001 &5352000285921552497 PrefabInstance: m_ObjectHideFlags: 0 diff --git a/Assets/Thirdweb/Runtime/Unity/Prefabs/ThirdwebManagerServer.prefab b/Assets/Thirdweb/Runtime/Unity/Prefabs/ThirdwebManagerServer.prefab new file mode 100644 index 000000000..88cb514fa --- /dev/null +++ b/Assets/Thirdweb/Runtime/Unity/Prefabs/ThirdwebManagerServer.prefab @@ -0,0 +1,55 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2985666425045432145 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7977017408921700919} + - component: {fileID: 5964706357837968276} + m_Layer: 0 + m_Name: ThirdwebManagerServer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7977017408921700919 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2985666425045432145} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &5964706357837968276 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2985666425045432145} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a197f9da6b1311840bb25b207982e287, type: 3} + m_Name: + m_EditorClassIdentifier: + k__BackingField: 1 + k__BackingField: 1 + k__BackingField: 0 + k__BackingField: 0 + k__BackingField: ee6e060000000000 + k__BackingField: [] + k__BackingField: + k__BackingField: [] + k__BackingField: diff --git a/Assets/Thirdweb/Runtime/Unity/Prefabs/ThirdwebManagerServer.prefab.meta b/Assets/Thirdweb/Runtime/Unity/Prefabs/ThirdwebManagerServer.prefab.meta new file mode 100644 index 000000000..8d4427048 --- /dev/null +++ b/Assets/Thirdweb/Runtime/Unity/Prefabs/ThirdwebManagerServer.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: afb575e501b7e2342b3080838f0545cb +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Thirdweb/Runtime/Unity/ThirdwebManager.cs b/Assets/Thirdweb/Runtime/Unity/ThirdwebManager.cs index 619c484bd..51579e4e8 100644 --- a/Assets/Thirdweb/Runtime/Unity/ThirdwebManager.cs +++ b/Assets/Thirdweb/Runtime/Unity/ThirdwebManager.cs @@ -1,144 +1,10 @@ -using UnityEngine; -using System.Collections.Generic; -using System.Numerics; -using System.Threading.Tasks; using System.Linq; -using System; -using System.IO; +using System.Numerics; +using UnityEngine; namespace Thirdweb.Unity { - public enum WalletProvider - { - PrivateKeyWallet, - InAppWallet, - WalletConnectWallet, - MetaMaskWallet, - EcosystemWallet - } - - public class InAppWalletOptions - { - public string Email; - public string PhoneNumber; - public AuthProvider AuthProvider; - public string JwtOrPayload; - public string LegacyEncryptionKey; - public string StorageDirectoryPath; - public IThirdwebWallet SiweSigner; - - public InAppWalletOptions( - string email = null, - string phoneNumber = null, - AuthProvider authprovider = AuthProvider.Default, - string jwtOrPayload = null, - string legacyEncryptionKey = null, - string storageDirectoryPath = null, - IThirdwebWallet siweSigner = null - ) - { - Email = email; - PhoneNumber = phoneNumber; - AuthProvider = authprovider; - JwtOrPayload = jwtOrPayload; - LegacyEncryptionKey = legacyEncryptionKey; - StorageDirectoryPath = storageDirectoryPath ?? Path.Combine(Application.persistentDataPath, "Thirdweb", "InAppWallet"); - SiweSigner = siweSigner; - } - } - - public class EcosystemWalletOptions - { - public string EcosystemId; - public string EcosystemPartnerId; - public string Email; - public string PhoneNumber; - public AuthProvider AuthProvider; - public string JwtOrPayload; - public string StorageDirectoryPath; - public IThirdwebWallet SiweSigner; - public string LegacyEncryptionKey; - - public EcosystemWalletOptions( - string ecosystemId = null, - string ecosystemPartnerId = null, - string email = null, - string phoneNumber = null, - AuthProvider authprovider = AuthProvider.Default, - string jwtOrPayload = null, - string storageDirectoryPath = null, - IThirdwebWallet siweSigner = null, - string legacyEncryptionKey = null - ) - { - EcosystemId = ecosystemId; - EcosystemPartnerId = ecosystemPartnerId; - Email = email; - PhoneNumber = phoneNumber; - AuthProvider = authprovider; - JwtOrPayload = jwtOrPayload; - StorageDirectoryPath = storageDirectoryPath ?? Path.Combine(Application.persistentDataPath, "Thirdweb", "EcosystemWallet"); - SiweSigner = siweSigner; - LegacyEncryptionKey = legacyEncryptionKey; - } - } - - public class SmartWalletOptions - { - public bool SponsorGas; - public string FactoryAddress; - public string AccountAddressOverride; - public string EntryPoint; - public string BundlerUrl; - public string PaymasterUrl; - public TokenPaymaster TokenPaymaster; - - public SmartWalletOptions( - bool sponsorGas, - string factoryAddress = null, - string accountAddressOverride = null, - string entryPoint = null, - string bundlerUrl = null, - string paymasterUrl = null, - TokenPaymaster tokenPaymaster = TokenPaymaster.NONE - ) - { - SponsorGas = sponsorGas; - FactoryAddress = factoryAddress; - AccountAddressOverride = accountAddressOverride; - EntryPoint = entryPoint; - BundlerUrl = bundlerUrl; - PaymasterUrl = paymasterUrl; - TokenPaymaster = tokenPaymaster; - } - } - - public class WalletOptions - { - public WalletProvider Provider; - public BigInteger ChainId; - public InAppWalletOptions InAppWalletOptions; - public EcosystemWalletOptions EcosystemWalletOptions; - public SmartWalletOptions SmartWalletOptions; - - public WalletOptions( - WalletProvider provider, - BigInteger chainId, - InAppWalletOptions inAppWalletOptions = null, - EcosystemWalletOptions ecosystemWalletOptions = null, - SmartWalletOptions smartWalletOptions = null - ) - { - Provider = provider; - ChainId = chainId; - InAppWalletOptions = inAppWalletOptions ?? new InAppWalletOptions(); - SmartWalletOptions = smartWalletOptions; - EcosystemWalletOptions = ecosystemWalletOptions; - } - } - - [HelpURL("http://portal.thirdweb.com/unity/v5/thirdwebmanager")] - public class ThirdwebManager : MonoBehaviour + public class ThirdwebManager : ThirdwebManagerBase { [field: SerializeField] private string ClientId { get; set; } @@ -146,380 +12,40 @@ public class ThirdwebManager : MonoBehaviour [field: SerializeField] private string BundleId { get; set; } - [field: SerializeField] - private bool InitializeOnAwake { get; set; } = true; - - [field: SerializeField] - private bool ShowDebugLogs { get; set; } = true; - - [field: SerializeField] - private bool OptOutUsageAnalytics { get; set; } = false; - - [field: SerializeField] - private ulong[] SupportedChains { get; set; } = new ulong[] { 421614 }; - - [field: SerializeField] - private string RedirectPageHtmlOverride { get; set; } = null; - - public ThirdwebClient Client { get; private set; } - - public IThirdwebWallet ActiveWallet { get; private set; } - - public static ThirdwebManager Instance { get; private set; } - - public static readonly string THIRDWEB_UNITY_SDK_VERSION = "5.9.0"; - - private bool _initialized; - - private Dictionary _walletMapping; - - private void Awake() + public static new ThirdwebManager Instance { - if (Instance == null) - { - Instance = this; - DontDestroyOnLoad(gameObject); - } - else - { - Destroy(gameObject); - return; - } - - ThirdwebDebug.IsEnabled = ShowDebugLogs; - - if (InitializeOnAwake) - { - Initialize(); - } + get => ThirdwebManagerBase.Instance as ThirdwebManager; } - public void Initialize() + protected override ThirdwebClient CreateClient() { - if (string.IsNullOrEmpty(ClientId)) + if (string.IsNullOrWhiteSpace(ClientId)) { - ThirdwebDebug.LogError("ClientId and must be set in order to initialize ThirdwebManager. Get your API key from https://thirdweb.com/create-api-key"); - return; + ThirdwebDebug.LogError("ClientId must be set in order to initialize ThirdwebManager. " + "Get your API key from https://thirdweb.com/create-api-key"); + return null; } - if (string.IsNullOrEmpty(BundleId)) + if (string.IsNullOrWhiteSpace(BundleId)) { BundleId = null; } - BundleId ??= Application.identifier ?? $"com.{Application.companyName}.{Application.productName}"; + BundleId ??= string.IsNullOrWhiteSpace(Application.identifier) ? $"com.{Application.companyName}.{Application.productName}" : Application.identifier; - Client = ThirdwebClient.Create( + return ThirdwebClient.Create( clientId: ClientId, bundleId: BundleId, httpClient: new CrossPlatformUnityHttpClient(), sdkName: Application.platform == RuntimePlatform.WebGLPlayer ? "UnitySDK_WebGL" : "UnitySDK", sdkOs: Application.platform.ToString(), sdkPlatform: "unity", - sdkVersion: THIRDWEB_UNITY_SDK_VERSION - ); - - ThirdwebDebug.Log("ThirdwebManager initialized."); - - _walletMapping = new Dictionary(); - - _initialized = true; - } - - public async Task GetContract(string address, BigInteger chainId, string abi = null) - { - if (!_initialized) - { - throw new InvalidOperationException("ThirdwebManager is not initialized."); - } - - return await ThirdwebContract.Create(Client, address, chainId, abi); - } - - public IThirdwebWallet GetActiveWallet() - { - return ActiveWallet; - } - - public void SetActiveWallet(IThirdwebWallet wallet) - { - ActiveWallet = wallet; - } - - public IThirdwebWallet GetWallet(string address) - { - if (_walletMapping.TryGetValue(address, out var wallet)) - { - return wallet; - } - - throw new KeyNotFoundException($"Wallet with address {address} not found."); - } - - public async Task AddWallet(IThirdwebWallet wallet) - { - var address = await wallet.GetAddress(); - _walletMapping.TryAdd(address, wallet); - return wallet; - } - - public void RemoveWallet(string address) - { - if (_walletMapping.ContainsKey(address)) - { - _walletMapping.Remove(address, out var wallet); - } - } - - public async Task ConnectWallet(WalletOptions walletOptions) - { - if (!_initialized) - { - throw new InvalidOperationException("ThirdwebManager is not initialized."); - } - - if (walletOptions == null) - { - throw new ArgumentNullException(nameof(walletOptions)); - } - - if (walletOptions.ChainId <= 0) - { - throw new ArgumentException("ChainId must be greater than 0."); - } - - IThirdwebWallet wallet = null; - - switch (walletOptions.Provider) - { - case WalletProvider.PrivateKeyWallet: - wallet = await PrivateKeyWallet.Generate(client: Client); - break; - case WalletProvider.InAppWallet: - wallet = await InAppWallet.Create( - client: Client, - email: walletOptions.InAppWalletOptions.Email, - phoneNumber: walletOptions.InAppWalletOptions.PhoneNumber, - authProvider: walletOptions.InAppWalletOptions.AuthProvider, - storageDirectoryPath: walletOptions.InAppWalletOptions.StorageDirectoryPath, - siweSigner: walletOptions.InAppWalletOptions.SiweSigner, - legacyEncryptionKey: walletOptions.InAppWalletOptions.LegacyEncryptionKey - ); - break; - case WalletProvider.EcosystemWallet: - if (walletOptions.EcosystemWalletOptions == null) - { - throw new ArgumentException("EcosystemWalletOptions must be provided for EcosystemWallet provider."); - } - if (string.IsNullOrEmpty(walletOptions.EcosystemWalletOptions.EcosystemId)) - { - throw new ArgumentException("EcosystemId must be provided for EcosystemWallet provider."); - } - wallet = await EcosystemWallet.Create( - client: Client, - ecosystemId: walletOptions.EcosystemWalletOptions.EcosystemId, - ecosystemPartnerId: walletOptions.EcosystemWalletOptions.EcosystemPartnerId, - email: walletOptions.EcosystemWalletOptions.Email, - phoneNumber: walletOptions.EcosystemWalletOptions.PhoneNumber, - authProvider: walletOptions.EcosystemWalletOptions.AuthProvider, - storageDirectoryPath: walletOptions.EcosystemWalletOptions.StorageDirectoryPath, - siweSigner: walletOptions.EcosystemWalletOptions.SiweSigner, - legacyEncryptionKey: walletOptions.EcosystemWalletOptions.LegacyEncryptionKey - ); - break; - case WalletProvider.WalletConnectWallet: - var supportedChains = SupportedChains.Select(chain => new BigInteger(chain)).ToArray(); - wallet = await WalletConnectWallet.Create(client: Client, initialChainId: walletOptions.ChainId, supportedChains: supportedChains); - break; - case WalletProvider.MetaMaskWallet: - wallet = await MetaMaskWallet.Create(client: Client, activeChainId: walletOptions.ChainId); - break; - } - - if (walletOptions.Provider == WalletProvider.InAppWallet && !await wallet.IsConnected()) - { - ThirdwebDebug.Log("Session does not exist or is expired, proceeding with InAppWallet authentication."); - - var inAppWallet = wallet as InAppWallet; - - if (walletOptions.InAppWalletOptions.AuthProvider == AuthProvider.Default) - { - await inAppWallet.SendOTP(); - _ = await InAppWalletModal.LoginWithOtp(inAppWallet); - } - else if (walletOptions.InAppWalletOptions.AuthProvider == AuthProvider.Siwe) - { - _ = await inAppWallet.LoginWithSiwe(walletOptions.ChainId); - } - else if (walletOptions.InAppWalletOptions.AuthProvider == AuthProvider.JWT) - { - _ = await inAppWallet.LoginWithJWT(walletOptions.InAppWalletOptions.JwtOrPayload); - } - else if (walletOptions.InAppWalletOptions.AuthProvider == AuthProvider.AuthEndpoint) - { - _ = await inAppWallet.LoginWithAuthEndpoint(walletOptions.InAppWalletOptions.JwtOrPayload); - } - else if (walletOptions.InAppWalletOptions.AuthProvider == AuthProvider.Guest) - { - _ = await inAppWallet.LoginWithGuest(); - } - else - { - _ = await inAppWallet.LoginWithOauth( - isMobile: Application.isMobilePlatform, - browserOpenAction: (url) => Application.OpenURL(url), - mobileRedirectScheme: BundleId + "://", - browser: new CrossPlatformUnityBrowser(RedirectPageHtmlOverride) - ); - } - } - - if (walletOptions.Provider == WalletProvider.EcosystemWallet && !await wallet.IsConnected()) - { - ThirdwebDebug.Log("Session does not exist or is expired, proceeding with EcosystemWallet authentication."); - - var ecosystemWallet = wallet as EcosystemWallet; - - if (walletOptions.EcosystemWalletOptions.AuthProvider == AuthProvider.Default) - { - await ecosystemWallet.SendOTP(); - _ = await EcosystemWalletModal.LoginWithOtp(ecosystemWallet); - } - else if (walletOptions.EcosystemWalletOptions.AuthProvider == AuthProvider.Siwe) - { - _ = await ecosystemWallet.LoginWithSiwe(walletOptions.ChainId); - } - else if (walletOptions.EcosystemWalletOptions.AuthProvider == AuthProvider.JWT) - { - _ = await ecosystemWallet.LoginWithJWT(walletOptions.EcosystemWalletOptions.JwtOrPayload); - } - else if (walletOptions.EcosystemWalletOptions.AuthProvider == AuthProvider.AuthEndpoint) - { - _ = await ecosystemWallet.LoginWithAuthEndpoint(walletOptions.EcosystemWalletOptions.JwtOrPayload); - } - else if (walletOptions.EcosystemWalletOptions.AuthProvider == AuthProvider.Guest) - { - _ = await ecosystemWallet.LoginWithGuest(); - } - else - { - _ = await ecosystemWallet.LoginWithOauth( - isMobile: Application.isMobilePlatform, - browserOpenAction: (url) => Application.OpenURL(url), - mobileRedirectScheme: BundleId + "://", - browser: new CrossPlatformUnityBrowser(RedirectPageHtmlOverride) - ); - } - } - - var address = await wallet.GetAddress(); - ThirdwebDebug.Log($"Wallet address: {address}"); - - var isSmartWallet = walletOptions.SmartWalletOptions != null; - - if (!OptOutUsageAnalytics) - { - TrackUsage("connectWallet", "connect", isSmartWallet ? "smartWallet" : walletOptions.Provider.ToString()[..1].ToLower() + walletOptions.Provider.ToString()[1..], address); - } - - if (isSmartWallet) - { - ThirdwebDebug.Log("Upgrading to SmartWallet."); - return await UpgradeToSmartWallet(wallet, walletOptions.ChainId, walletOptions.SmartWalletOptions); - } - else - { - await AddWallet(wallet); - SetActiveWallet(wallet); - return wallet; - } - } - - public async Task UpgradeToSmartWallet(IThirdwebWallet personalWallet, BigInteger chainId, SmartWalletOptions smartWalletOptions) - { - if (!_initialized) - { - throw new InvalidOperationException("ThirdwebManager is not initialized."); - } - - if (personalWallet.AccountType == ThirdwebAccountType.SmartAccount) - { - ThirdwebDebug.LogWarning("Wallet is already a SmartWallet."); - return personalWallet as SmartWallet; - } - - if (smartWalletOptions == null) - { - throw new ArgumentNullException(nameof(smartWalletOptions)); - } - - if (chainId <= 0) - { - throw new ArgumentException("ChainId must be greater than 0."); - } - - var wallet = await SmartWallet.Create( - personalWallet: personalWallet, - chainId: chainId, - gasless: smartWalletOptions.SponsorGas, - factoryAddress: smartWalletOptions.FactoryAddress, - accountAddressOverride: smartWalletOptions.AccountAddressOverride, - entryPoint: smartWalletOptions.EntryPoint, - bundlerUrl: smartWalletOptions.BundlerUrl, - paymasterUrl: smartWalletOptions.PaymasterUrl, - tokenPaymaster: smartWalletOptions.TokenPaymaster - ); - - await AddWallet(wallet); - SetActiveWallet(wallet); - - return wallet; - } - - public async Task> LinkAccount(IThirdwebWallet mainWallet, IThirdwebWallet walletToLink, string otp = null, BigInteger? chainId = null, string jwtOrPayload = null) - { - return await mainWallet.LinkAccount( - walletToLink: walletToLink, - otp: otp, - isMobile: Application.isMobilePlatform, - browserOpenAction: (url) => Application.OpenURL(url), - mobileRedirectScheme: BundleId + "://", - browser: new CrossPlatformUnityBrowser(RedirectPageHtmlOverride), - chainId: chainId, - jwt: jwtOrPayload, - payload: jwtOrPayload + sdkVersion: THIRDWEB_UNITY_SDK_VERSION, + rpcOverrides: (RpcOverrides == null || RpcOverrides.Count == 0) + ? null + : RpcOverrides.ToDictionary(rpcOverride => new BigInteger(rpcOverride.ChainId), rpcOverride => rpcOverride.RpcUrl) ); } - private async void TrackUsage(string source, string action, string walletType, string walletAddress) - { - if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(action) || string.IsNullOrEmpty(walletType) || string.IsNullOrEmpty(walletAddress)) - { - ThirdwebDebug.LogWarning("Invalid usage analytics parameters."); - return; - } - - try - { - var content = new System.Net.Http.StringContent( - Newtonsoft.Json.JsonConvert.SerializeObject( - new - { - source, - action, - walletAddress, - walletType, - } - ), - System.Text.Encoding.UTF8, - "application/json" - ); - _ = await Client.HttpClient.PostAsync("https://c.thirdweb.com/event", content); - } - catch - { - ThirdwebDebug.LogWarning($"Failed to report usage analytics."); - } - } + protected override string MobileRedirectScheme => BundleId + "://"; } } diff --git a/Assets/Thirdweb/Runtime/Unity/ThirdwebManagerBase.cs b/Assets/Thirdweb/Runtime/Unity/ThirdwebManagerBase.cs new file mode 100644 index 000000000..514e0b77c --- /dev/null +++ b/Assets/Thirdweb/Runtime/Unity/ThirdwebManagerBase.cs @@ -0,0 +1,649 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Numerics; +using System.Threading.Tasks; +using Newtonsoft.Json; +using UnityEngine; + +namespace Thirdweb.Unity +{ + [Serializable] + public enum WalletProvider + { + PrivateKeyWallet, + InAppWallet, + WalletConnectWallet, + MetaMaskWallet, + EcosystemWallet, + } + + [Serializable] + public class InAppWalletOptions : EcosystemWalletOptions + { + public InAppWalletOptions( + string email = null, + string phoneNumber = null, + AuthProvider authprovider = AuthProvider.Default, + string jwtOrPayload = null, + string storageDirectoryPath = null, + IThirdwebWallet siweSigner = null, + string legacyEncryptionKey = null, + string walletSecret = null, + List forceSiweExternalWalletIds = null, + ExecutionMode executionMode = ExecutionMode.EOA + ) + : base( + email: email, + phoneNumber: phoneNumber, + authprovider: authprovider, + jwtOrPayload: jwtOrPayload, + storageDirectoryPath: storageDirectoryPath, + siweSigner: siweSigner, + legacyEncryptionKey: legacyEncryptionKey, + walletSecret: walletSecret, + forceSiweExternalWalletIds: forceSiweExternalWalletIds, + executionMode: executionMode + ) { } + } + + [Serializable] + public class EcosystemWalletOptions + { + [JsonProperty("ecosystemId")] + public string EcosystemId; + + [JsonProperty("ecosystemPartnerId")] + public string EcosystemPartnerId; + + [JsonProperty("email")] + public string Email; + + [JsonProperty("phoneNumber")] + public string PhoneNumber; + + [JsonProperty("authProvider")] + public AuthProvider AuthProvider; + + [JsonProperty("jwtOrPayload")] + public string JwtOrPayload; + + [JsonProperty("storageDirectoryPath")] + public string StorageDirectoryPath; + + [JsonProperty("siweSigner")] + public IThirdwebWallet SiweSigner; + + [JsonProperty("legacyEncryptionKey")] + public string LegacyEncryptionKey; + + [JsonProperty("walletSecret")] + public string WalletSecret; + + [JsonProperty("forceSiweExternalWalletIds")] + public List ForceSiweExternalWalletIds; + + [JsonProperty("executionMode")] + public ExecutionMode ExecutionMode = ExecutionMode.EOA; + + public EcosystemWalletOptions( + string ecosystemId = null, + string ecosystemPartnerId = null, + string email = null, + string phoneNumber = null, + AuthProvider authprovider = AuthProvider.Default, + string jwtOrPayload = null, + string storageDirectoryPath = null, + IThirdwebWallet siweSigner = null, + string legacyEncryptionKey = null, + string walletSecret = null, + List forceSiweExternalWalletIds = null, + ExecutionMode executionMode = ExecutionMode.EOA + ) + { + EcosystemId = ecosystemId; + EcosystemPartnerId = ecosystemPartnerId; + Email = email; + PhoneNumber = phoneNumber; + AuthProvider = authprovider; + JwtOrPayload = jwtOrPayload; + StorageDirectoryPath = storageDirectoryPath ?? Path.Combine(Application.persistentDataPath, "Thirdweb", "EcosystemWallet"); + SiweSigner = siweSigner; + LegacyEncryptionKey = legacyEncryptionKey; + WalletSecret = walletSecret; + ForceSiweExternalWalletIds = forceSiweExternalWalletIds; + ExecutionMode = executionMode; + } + } + + [Serializable] + public class SmartWalletOptions + { + [JsonProperty("sponsorGas")] + public bool SponsorGas; + + [JsonProperty("factoryAddress")] + public string FactoryAddress; + + [JsonProperty("accountAddressOverride")] + public string AccountAddressOverride; + + [JsonProperty("entryPoint")] + public string EntryPoint; + + [JsonProperty("bundlerUrl")] + public string BundlerUrl; + + [JsonProperty("paymasterUrl")] + public string PaymasterUrl; + + [JsonProperty("tokenPaymaster")] + public TokenPaymaster TokenPaymaster; + + public SmartWalletOptions( + bool sponsorGas, + string factoryAddress = null, + string accountAddressOverride = null, + string entryPoint = null, + string bundlerUrl = null, + string paymasterUrl = null, + TokenPaymaster tokenPaymaster = TokenPaymaster.NONE + ) + { + SponsorGas = sponsorGas; + FactoryAddress = factoryAddress; + AccountAddressOverride = accountAddressOverride; + EntryPoint = entryPoint; + BundlerUrl = bundlerUrl; + PaymasterUrl = paymasterUrl; + TokenPaymaster = tokenPaymaster; + } + } + + [Serializable] + public class WalletOptions + { + [JsonProperty("provider")] + public WalletProvider Provider; + + [JsonProperty("chainId")] + public BigInteger ChainId; + + [JsonProperty("inAppWalletOptions")] + public InAppWalletOptions InAppWalletOptions; + + [JsonProperty("ecosystemWalletOptions", NullValueHandling = NullValueHandling.Ignore)] + public EcosystemWalletOptions EcosystemWalletOptions; + + [JsonProperty("smartWalletOptions", NullValueHandling = NullValueHandling.Ignore)] + public SmartWalletOptions SmartWalletOptions; + + public WalletOptions( + WalletProvider provider, + BigInteger chainId, + InAppWalletOptions inAppWalletOptions = null, + EcosystemWalletOptions ecosystemWalletOptions = null, + SmartWalletOptions smartWalletOptions = null + ) + { + Provider = provider; + ChainId = chainId; + InAppWalletOptions = inAppWalletOptions ?? new InAppWalletOptions(); + SmartWalletOptions = smartWalletOptions; + EcosystemWalletOptions = ecosystemWalletOptions; + } + } + + [Serializable] + public struct RpcOverride + { + public ulong ChainId; + public string RpcUrl; + } + + [HelpURL("http://portal.thirdweb.com/unity/v5/thirdwebmanager")] + public abstract class ThirdwebManagerBase : MonoBehaviour + { + [field: SerializeField] + protected bool InitializeOnAwake { get; set; } = true; + + [field: SerializeField] + protected bool ShowDebugLogs { get; set; } = true; + + [field: SerializeField] + protected bool AutoConnectLastWallet { get; set; } = false; + + [field: SerializeField] + protected ulong[] SupportedChains { get; set; } = new ulong[] { 421614 }; + + [field: SerializeField] + protected string[] IncludedWalletIds { get; set; } = null; + + [field: SerializeField] + protected string RedirectPageHtmlOverride { get; set; } = null; + + [field: SerializeField] + protected List RpcOverrides { get; set; } = null; + + public ThirdwebClient Client { get; protected set; } + public IThirdwebWallet ActiveWallet { get; protected set; } + public bool Initialized { get; protected set; } + + public static ThirdwebManagerBase Instance { get; protected set; } + + public static readonly string THIRDWEB_UNITY_SDK_VERSION = "5.26.0"; + + protected const string THIRDWEB_AUTO_CONNECT_OPTIONS_KEY = "ThirdwebAutoConnectOptions"; + + protected Dictionary _walletMapping; + + protected abstract ThirdwebClient CreateClient(); + + protected abstract string MobileRedirectScheme { get; } + + // ------------------------------------------------------ + // Lifecycle Methods + // ------------------------------------------------------ + + protected virtual void Awake() + { + if (Instance == null) + { + Instance = this; + DontDestroyOnLoad(gameObject); + } + else + { + Destroy(gameObject); + return; + } + + ThirdwebDebug.IsEnabled = ShowDebugLogs; + + if (InitializeOnAwake) + { + Initialize(); + } + } + + public virtual async void Initialize() + { + Client = CreateClient(); + if (Client == null) + { + ThirdwebDebug.LogError("Failed to initialize ThirdwebManager."); + return; + } + + ThirdwebDebug.Log("ThirdwebManager initialized."); + + _walletMapping = new Dictionary(); + + if (AutoConnectLastWallet && GetAutoConnectOptions(out var lastWalletOptions)) + { + ThirdwebDebug.Log("Auto-connecting to last wallet."); + try + { + _ = await ConnectWallet(lastWalletOptions); + ThirdwebDebug.Log("Auto-connected to last wallet."); + } + catch (Exception e) + { + ThirdwebDebug.LogError("Failed to auto-connect to last wallet: " + e.Message); + } + } + + Initialized = true; + } + + // ------------------------------------------------------ + // Contract Methods + // ------------------------------------------------------ + + public virtual async Task GetContract(string address, BigInteger chainId, string abi = null) + { + if (!Initialized) + { + throw new InvalidOperationException("ThirdwebManager is not initialized."); + } + + return await ThirdwebContract.Create(Client, address, chainId, abi); + } + + // ------------------------------------------------------ + // Active Wallet Methods + // ------------------------------------------------------ + + public virtual IThirdwebWallet GetActiveWallet() + { + return ActiveWallet; + } + + public virtual void SetActiveWallet(IThirdwebWallet wallet) + { + ActiveWallet = wallet; + } + + public virtual IThirdwebWallet GetWallet(string address) + { + if (_walletMapping.TryGetValue(address, out var wallet)) + { + return wallet; + } + + throw new KeyNotFoundException($"Wallet with address {address} not found."); + } + + public virtual async Task AddWallet(IThirdwebWallet wallet) + { + var address = await wallet.GetAddress(); + _walletMapping.TryAdd(address, wallet); + return wallet; + } + + public virtual void RemoveWallet(string address) + { + if (_walletMapping.ContainsKey(address)) + { + _walletMapping.Remove(address, out var _); + } + } + + // ------------------------------------------------------ + // Connection Methods + // ------------------------------------------------------ + + public virtual async Task ConnectWallet(WalletOptions walletOptions) + { + if (walletOptions == null) + { + throw new ArgumentNullException(nameof(walletOptions)); + } + + if (walletOptions.ChainId <= 0) + { + throw new ArgumentException("ChainId must be greater than 0."); + } + + IThirdwebWallet wallet = null; + + switch (walletOptions.Provider) + { + case WalletProvider.PrivateKeyWallet: + wallet = await PrivateKeyWallet.Generate(client: Client); + break; + + case WalletProvider.InAppWallet: + wallet = await InAppWallet.Create( + client: Client, + email: walletOptions.InAppWalletOptions.Email, + phoneNumber: walletOptions.InAppWalletOptions.PhoneNumber, + authProvider: walletOptions.InAppWalletOptions.AuthProvider, + storageDirectoryPath: walletOptions.InAppWalletOptions.StorageDirectoryPath, + siweSigner: walletOptions.InAppWalletOptions.SiweSigner, + legacyEncryptionKey: walletOptions.InAppWalletOptions.LegacyEncryptionKey, + walletSecret: walletOptions.InAppWalletOptions.WalletSecret, + executionMode: walletOptions.InAppWalletOptions.ExecutionMode + ); + break; + + case WalletProvider.EcosystemWallet: + if (walletOptions.EcosystemWalletOptions == null) + { + throw new ArgumentException("EcosystemWalletOptions must be provided for EcosystemWallet provider."); + } + if (string.IsNullOrEmpty(walletOptions.EcosystemWalletOptions.EcosystemId)) + { + throw new ArgumentException("EcosystemId must be provided for EcosystemWallet provider."); + } + wallet = await EcosystemWallet.Create( + client: Client, + ecosystemId: walletOptions.EcosystemWalletOptions.EcosystemId, + ecosystemPartnerId: walletOptions.EcosystemWalletOptions.EcosystemPartnerId, + email: walletOptions.EcosystemWalletOptions.Email, + phoneNumber: walletOptions.EcosystemWalletOptions.PhoneNumber, + authProvider: walletOptions.EcosystemWalletOptions.AuthProvider, + storageDirectoryPath: walletOptions.EcosystemWalletOptions.StorageDirectoryPath, + siweSigner: walletOptions.EcosystemWalletOptions.SiweSigner, + legacyEncryptionKey: walletOptions.EcosystemWalletOptions.LegacyEncryptionKey, + walletSecret: walletOptions.EcosystemWalletOptions.WalletSecret, + executionMode: walletOptions.EcosystemWalletOptions.ExecutionMode + ); + break; + + case WalletProvider.WalletConnectWallet: + var supportedChains = SupportedChains.Select(chain => new BigInteger(chain)).ToArray(); + var includedWalletIds = IncludedWalletIds == null || IncludedWalletIds.Length == 0 ? null : IncludedWalletIds; + wallet = await WalletConnectWallet.Create(client: Client, initialChainId: walletOptions.ChainId, supportedChains: supportedChains, includedWalletIds: includedWalletIds); + break; + + case WalletProvider.MetaMaskWallet: + wallet = await MetaMaskWallet.Create(client: Client, activeChainId: walletOptions.ChainId); + break; + } + + // InAppWallet auth flow + if (walletOptions.Provider == WalletProvider.InAppWallet && !await wallet.IsConnected()) + { + ThirdwebDebug.Log("Session does not exist or is expired, proceeding with InAppWallet authentication."); + + var inAppWallet = wallet as InAppWallet; + switch (walletOptions.InAppWalletOptions.AuthProvider) + { + case AuthProvider.Default: + await inAppWallet.SendOTP(); + _ = await InAppWalletModal.LoginWithOtp(inAppWallet); + break; + case AuthProvider.Siwe: + _ = await inAppWallet.LoginWithSiwe(walletOptions.ChainId); + break; + case AuthProvider.JWT: + _ = await inAppWallet.LoginWithJWT(walletOptions.InAppWalletOptions.JwtOrPayload); + break; + case AuthProvider.AuthEndpoint: + _ = await inAppWallet.LoginWithAuthEndpoint(walletOptions.InAppWalletOptions.JwtOrPayload); + break; + case AuthProvider.Guest: + _ = await inAppWallet.LoginWithGuest(SystemInfo.deviceUniqueIdentifier); + break; + case AuthProvider.Backend: + _ = await inAppWallet.LoginWithBackend(); + break; + case AuthProvider.SiweExternal: + _ = await inAppWallet.LoginWithSiweExternal( + isMobile: IsMobileRuntime(), + browserOpenAction: (url) => Application.OpenURL(url), + forceWalletIds: walletOptions.InAppWalletOptions.ForceSiweExternalWalletIds == null || walletOptions.InAppWalletOptions.ForceSiweExternalWalletIds.Count == 0 + ? null + : walletOptions.InAppWalletOptions.ForceSiweExternalWalletIds, + mobileRedirectScheme: MobileRedirectScheme, + browser: new CrossPlatformUnityBrowser(RedirectPageHtmlOverride) + ); + break; + default: + _ = await inAppWallet.LoginWithOauth( + isMobile: IsMobileRuntime(), + browserOpenAction: (url) => Application.OpenURL(url), + mobileRedirectScheme: MobileRedirectScheme, + browser: new CrossPlatformUnityBrowser(RedirectPageHtmlOverride) + ); + break; + } + } + + // EcosystemWallet auth flow + if (walletOptions.Provider == WalletProvider.EcosystemWallet && !await wallet.IsConnected()) + { + ThirdwebDebug.Log("Session does not exist or is expired, proceeding with EcosystemWallet authentication."); + + var ecosystemWallet = wallet as EcosystemWallet; + switch (walletOptions.EcosystemWalletOptions.AuthProvider) + { + case AuthProvider.Default: + await ecosystemWallet.SendOTP(); + _ = await EcosystemWalletModal.LoginWithOtp(ecosystemWallet); + break; + case AuthProvider.Siwe: + _ = await ecosystemWallet.LoginWithSiwe(walletOptions.ChainId); + break; + case AuthProvider.JWT: + _ = await ecosystemWallet.LoginWithJWT(walletOptions.EcosystemWalletOptions.JwtOrPayload); + break; + case AuthProvider.AuthEndpoint: + _ = await ecosystemWallet.LoginWithAuthEndpoint(walletOptions.EcosystemWalletOptions.JwtOrPayload); + break; + case AuthProvider.Guest: + _ = await ecosystemWallet.LoginWithGuest(SystemInfo.deviceUniqueIdentifier); + break; + case AuthProvider.Backend: + _ = await ecosystemWallet.LoginWithBackend(); + break; + case AuthProvider.SiweExternal: + _ = await ecosystemWallet.LoginWithSiweExternal( + isMobile: IsMobileRuntime(), + browserOpenAction: (url) => Application.OpenURL(url), + forceWalletIds: walletOptions.EcosystemWalletOptions.ForceSiweExternalWalletIds == null || walletOptions.EcosystemWalletOptions.ForceSiweExternalWalletIds.Count == 0 + ? null + : walletOptions.EcosystemWalletOptions.ForceSiweExternalWalletIds, + mobileRedirectScheme: MobileRedirectScheme, + browser: new CrossPlatformUnityBrowser(RedirectPageHtmlOverride) + ); + break; + default: + _ = await ecosystemWallet.LoginWithOauth( + isMobile: IsMobileRuntime(), + browserOpenAction: (url) => Application.OpenURL(url), + mobileRedirectScheme: MobileRedirectScheme, + browser: new CrossPlatformUnityBrowser(RedirectPageHtmlOverride) + ); + break; + } + } + + var address = await wallet.GetAddress(); + var isSmartWallet = walletOptions.SmartWalletOptions != null; + + SetAutoConnectOptions(walletOptions); + + // If SmartWallet, do upgrade + if (isSmartWallet) + { + ThirdwebDebug.Log("Upgrading to SmartWallet."); + return await UpgradeToSmartWallet(wallet, walletOptions.ChainId, walletOptions.SmartWalletOptions); + } + else + { + await AddWallet(wallet); + SetActiveWallet(wallet); + return wallet; + } + } + + public virtual async Task UpgradeToSmartWallet(IThirdwebWallet personalWallet, BigInteger chainId, SmartWalletOptions smartWalletOptions) + { + if (personalWallet.AccountType == ThirdwebAccountType.SmartAccount) + { + ThirdwebDebug.LogWarning("Wallet is already a SmartWallet."); + return personalWallet as SmartWallet; + } + + if (smartWalletOptions == null) + { + throw new ArgumentNullException(nameof(smartWalletOptions)); + } + + if (chainId <= 0) + { + throw new ArgumentException("ChainId must be greater than 0."); + } + + var wallet = await SmartWallet.Create( + personalWallet: personalWallet, + chainId: chainId, + gasless: smartWalletOptions.SponsorGas, + factoryAddress: smartWalletOptions.FactoryAddress, + accountAddressOverride: smartWalletOptions.AccountAddressOverride, + entryPoint: smartWalletOptions.EntryPoint, + bundlerUrl: smartWalletOptions.BundlerUrl, + paymasterUrl: smartWalletOptions.PaymasterUrl, + tokenPaymaster: smartWalletOptions.TokenPaymaster + ); + + await AddWallet(wallet); + SetActiveWallet(wallet); + + // Persist "smartWalletOptions" to auto-connect + if (AutoConnectLastWallet && GetAutoConnectOptions(out var lastWalletOptions)) + { + lastWalletOptions.SmartWalletOptions = smartWalletOptions; + SetAutoConnectOptions(lastWalletOptions); + } + + return wallet; + } + + public virtual async Task> LinkAccount(IThirdwebWallet mainWallet, IThirdwebWallet walletToLink, string otp = null, BigInteger? chainId = null, string jwtOrPayload = null) + { + return await mainWallet.LinkAccount( + walletToLink: walletToLink, + otp: otp, + isMobile: IsMobileRuntime(), + browserOpenAction: (url) => Application.OpenURL(url), + mobileRedirectScheme: MobileRedirectScheme, + browser: new CrossPlatformUnityBrowser(RedirectPageHtmlOverride), + chainId: chainId, + jwt: jwtOrPayload, + payload: jwtOrPayload + ); + } + + protected virtual bool IsMobileRuntime() + { + if (Application.platform == RuntimePlatform.OSXPlayer) + { + return true; + } + + return Application.isMobilePlatform; + } + + protected virtual bool GetAutoConnectOptions(out WalletOptions lastWalletOptions) + { + var connectOptionsStr = PlayerPrefs.GetString(THIRDWEB_AUTO_CONNECT_OPTIONS_KEY, null); + if (!string.IsNullOrEmpty(connectOptionsStr)) + { + try + { + lastWalletOptions = JsonConvert.DeserializeObject(connectOptionsStr); + return true; + } + catch + { + ThirdwebDebug.LogWarning("Failed to load last wallet options."); + PlayerPrefs.DeleteKey(THIRDWEB_AUTO_CONNECT_OPTIONS_KEY); + lastWalletOptions = null; + return false; + } + } + lastWalletOptions = null; + return false; + } + + protected virtual void SetAutoConnectOptions(WalletOptions walletOptions) + { + if (AutoConnectLastWallet && walletOptions.Provider != WalletProvider.WalletConnectWallet) + { + try + { + PlayerPrefs.SetString(THIRDWEB_AUTO_CONNECT_OPTIONS_KEY, JsonConvert.SerializeObject(walletOptions)); + } + catch + { + ThirdwebDebug.LogWarning("Failed to save last wallet options."); + PlayerPrefs.DeleteKey(THIRDWEB_AUTO_CONNECT_OPTIONS_KEY); + } + } + } + } +} diff --git a/Assets/Thirdweb/Runtime/Unity/ThirdwebManagerBase.cs.meta b/Assets/Thirdweb/Runtime/Unity/ThirdwebManagerBase.cs.meta new file mode 100644 index 000000000..44a30b218 --- /dev/null +++ b/Assets/Thirdweb/Runtime/Unity/ThirdwebManagerBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3bd1bb5e5d7733646a69989260142701 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Thirdweb/Runtime/Unity/ThirdwebManagerServer.cs b/Assets/Thirdweb/Runtime/Unity/ThirdwebManagerServer.cs new file mode 100644 index 000000000..b0ffb66e9 --- /dev/null +++ b/Assets/Thirdweb/Runtime/Unity/ThirdwebManagerServer.cs @@ -0,0 +1,40 @@ +using UnityEngine; +using System.Linq; +using System.Numerics; + +namespace Thirdweb.Unity +{ + public class ThirdwebManagerServer : ThirdwebManagerBase + { + [field: SerializeField] + private string SecretKey { get; set; } + + public new static ThirdwebManagerServer Instance + { + get => ThirdwebManagerBase.Instance as ThirdwebManagerServer; + } + + protected override ThirdwebClient CreateClient() + { + if (string.IsNullOrEmpty(SecretKey)) + { + ThirdwebDebug.LogError("SecretKey must be set in order to initialize ThirdwebManagerServer."); + return null; + } + + return ThirdwebClient.Create( + secretKey: SecretKey, + httpClient: new CrossPlatformUnityHttpClient(), + sdkName: Application.platform == RuntimePlatform.WebGLPlayer ? "UnitySDK_WebGL" : "UnitySDK", + sdkOs: Application.platform.ToString(), + sdkPlatform: "unity", + sdkVersion: THIRDWEB_UNITY_SDK_VERSION, + rpcOverrides: (RpcOverrides == null || RpcOverrides.Count == 0) + ? null + : RpcOverrides.ToDictionary(rpcOverride => new BigInteger(rpcOverride.ChainId), rpcOverride => rpcOverride.RpcUrl) + ); + } + + protected override string MobileRedirectScheme => "tw-server://"; + } +} diff --git a/Assets/Thirdweb/Runtime/Unity/ThirdwebManagerServer.cs.meta b/Assets/Thirdweb/Runtime/Unity/ThirdwebManagerServer.cs.meta new file mode 100644 index 000000000..241465399 --- /dev/null +++ b/Assets/Thirdweb/Runtime/Unity/ThirdwebManagerServer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a197f9da6b1311840bb25b207982e287 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Thirdweb/Runtime/Unity/ThirdwebUnityExtensions.cs b/Assets/Thirdweb/Runtime/Unity/ThirdwebUnityExtensions.cs index 7cea6b10c..cee6a71c2 100644 --- a/Assets/Thirdweb/Runtime/Unity/ThirdwebUnityExtensions.cs +++ b/Assets/Thirdweb/Runtime/Unity/ThirdwebUnityExtensions.cs @@ -1,13 +1,44 @@ +using System; using System.Numerics; using System.Threading.Tasks; using UnityEngine; using ZXing; using ZXing.QrCode; +#if UNITY_WEBGL +using System.Runtime.InteropServices; +#endif + namespace Thirdweb.Unity { public static class ThirdwebUnityExtensions { +#if UNITY_WEBGL + [DllImport("__Internal")] + private static extern string ThirdwebCopyBuffer(string text); +#endif + + public static void CopyToClipboard(this string text) + { + try + { + if (Application.platform == RuntimePlatform.WebGLPlayer) + { +#if UNITY_WEBGL + ThirdwebCopyBuffer(text); +#endif + } + else + { + GUIUtility.systemCopyBuffer = text; + } + } + catch (Exception e) + { + ThirdwebDebug.LogWarning($"Failed to copy to clipboard: {e}"); + } + } + public static async Task GetNFTSprite(this NFT nft, ThirdwebClient client) { var bytes = await nft.GetNFTImageBytes(client); @@ -25,7 +56,7 @@ public static async Task GetNFTSprite(this NFT nft, ThirdwebClient clien public static async Task UpgradeToSmartWallet(this IThirdwebWallet personalWallet, BigInteger chainId, SmartWalletOptions smartWalletOptions) { - return await ThirdwebManager.Instance.UpgradeToSmartWallet(personalWallet, chainId, smartWalletOptions); + return await ThirdwebManagerBase.Instance.UpgradeToSmartWallet(personalWallet, chainId, smartWalletOptions); } public static Texture2D ToQRTexture(this string textForEncoding, Color? fgColor = null, Color? bgColor = null, int width = 512, int height = 512) diff --git a/Assets/Thirdweb/Runtime/Unity/Wallets/Core/MetaMaskWallet.cs b/Assets/Thirdweb/Runtime/Unity/Wallets/Core/MetaMaskWallet.cs index 9038a18ac..be4257308 100644 --- a/Assets/Thirdweb/Runtime/Unity/Wallets/Core/MetaMaskWallet.cs +++ b/Assets/Thirdweb/Runtime/Unity/Wallets/Core/MetaMaskWallet.cs @@ -16,6 +16,7 @@ namespace Thirdweb.Unity public class MetaMaskWallet : IThirdwebWallet { public ThirdwebClient Client => _client; + public string WalletId => "metamask"; public ThirdwebAccountType AccountType => ThirdwebAccountType.ExternalAccount; private static ThirdwebClient _client; @@ -32,34 +33,37 @@ public static async Task Create(ThirdwebClient client, BigIntege } var metaMaskInstance = WebGLMetaMask.Instance; + var mmWallet = new MetaMaskWallet(); if (metaMaskInstance.IsConnected() && !string.IsNullOrEmpty(metaMaskInstance.GetAddress())) { ThirdwebDebug.Log("MetaMask already initialized."); - await EnsureCorrectNetwork(activeChainId); - return new MetaMaskWallet(); + await mmWallet.SwitchNetwork(activeChainId); } - - if (metaMaskInstance.IsMetaMaskAvailable()) + else { - ThirdwebDebug.Log("MetaMask is available. Enabling Ethereum..."); - var isEnabled = await metaMaskInstance.EnableEthereumAsync(); - ThirdwebDebug.Log($"Ethereum enabled: {isEnabled}"); - if (isEnabled && !string.IsNullOrEmpty(metaMaskInstance.GetAddress())) + if (metaMaskInstance.IsMetaMaskAvailable()) { - ThirdwebDebug.Log("MetaMask initialized successfully."); - await EnsureCorrectNetwork(activeChainId); - return new MetaMaskWallet(); + ThirdwebDebug.Log("MetaMask is available. Enabling Ethereum..."); + var isEnabled = await metaMaskInstance.EnableEthereumAsync(activeChainId); + ThirdwebDebug.Log($"Ethereum enabled: {isEnabled}"); + if (isEnabled && !string.IsNullOrEmpty(metaMaskInstance.GetAddress())) + { + ThirdwebDebug.Log("MetaMask initialized successfully."); + await mmWallet.SwitchNetwork(activeChainId); + } + else + { + throw new Exception("MetaMask initialization failed or address is empty."); + } } else { - throw new Exception("MetaMask initialization failed or address is empty."); + throw new Exception("MetaMask is not available."); } } - else - { - throw new Exception("MetaMask is not available."); - } + Utils.TrackConnection(mmWallet); + return mmWallet; } #region IThirdwebWallet @@ -113,19 +117,32 @@ public async Task SendTransaction(ThirdwebTransactionInput transaction) Method = "eth_sendTransaction", Params = new object[] { - new TransactionInput() - { - Nonce = transaction.Nonce, - From = await GetAddress(), - To = transaction.To, - Gas = transaction.Gas, - GasPrice = transaction.GasPrice, - Value = transaction.Value, - Data = transaction.Data, - MaxFeePerGas = transaction.MaxFeePerGas, - MaxPriorityFeePerGas = transaction.MaxPriorityFeePerGas, - ChainId = new HexBigInteger(WebGLMetaMask.Instance.GetActiveChainId()), - } + transaction.GasPrice == null + ? new + { + nonce = transaction.Nonce.HexValue, + from = await GetAddress(), + to = transaction.To, + gas = transaction.Gas.HexValue, + value = transaction.Value?.HexValue ?? "0x0", + data = transaction.Data, + maxFeePerGas = transaction.MaxFeePerGas.HexValue, + maxPriorityFeePerGas = transaction.MaxPriorityFeePerGas?.HexValue ?? "0x0", + chainId = WebGLMetaMask.Instance.GetActiveChainId().NumberToHex(), + type = "0x2" + } + : new + { + nonce = transaction.Nonce.HexValue, + from = await GetAddress(), + to = transaction.To, + gas = transaction.Gas.HexValue, + value = transaction.Value?.HexValue ?? "0x0", + data = transaction.Data, + gasPrice = transaction.GasPrice.HexValue, + chainId = WebGLMetaMask.Instance.GetActiveChainId().NumberToHex(), + type = "0x0" + } } }; return await WebGLMetaMask.Instance.RequestAsync(rpcRequest); @@ -188,10 +205,18 @@ public Task RecoverAddressFromTypedDataV4(T data, TypedData< throw new NotImplementedException(); } - public Task Disconnect() + public async Task Disconnect() { - ThirdwebDebug.Log("Disconnecting has no effect on this wallet."); - return Task.CompletedTask; + try + { + _ = await WebGLMetaMask.Instance.RequestAsync( + new RpcRequest { Method = "wallet_revokePermissions", Params = new object[] { new Dictionary { { "eth_accounts", new object() } } } } + ); + } + catch + { + // no-op + } } public Task> LinkAccount( @@ -203,7 +228,9 @@ public Task> LinkAccount( IThirdwebBrowser browser = null, BigInteger? chainId = null, string jwt = null, - string payload = null + string payload = null, + string defaultSessionIdOverride = null, + List forceWalletIds = null ) { throw new InvalidOperationException("LinkAccount is not supported by external wallets."); @@ -214,38 +241,76 @@ public Task> GetLinkedAccounts() throw new InvalidOperationException("GetLinkedAccounts is not supported by external wallets."); } + public Task> UnlinkAccount(LinkedAccount accountToUnlink) + { + throw new InvalidOperationException("UnlinkAccount is not supported by external wallets."); + } + + public Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute) + { + throw new InvalidOperationException("SignAuthorization is not supported by external wallets."); + } + + public async Task SwitchNetwork(BigInteger chainId) + { + if (WebGLMetaMask.Instance.GetActiveChainId() != chainId) + { + try + { + await SwitchNetworkInternal(chainId); + } + catch + { + await AddNetworkInternal(chainId); + if (WebGLMetaMask.Instance.GetActiveChainId() == chainId) + { + return; + } + try + { + await SwitchNetworkInternal(chainId); + } + catch + { + // no-op, later metamask extension versions do not necessarily require switching post adding + } + } + } + } + #endregion #region Network Switching + [Obsolete("Use IThirdwebWallet.SwitchNetwork instead.")] public static async Task EnsureCorrectNetwork(BigInteger chainId) { if (WebGLMetaMask.Instance.GetActiveChainId() != chainId) { try { - await SwitchNetwork(chainId); + await SwitchNetworkInternal(chainId); } catch { - await AddNetwork(chainId); + await AddNetworkInternal(chainId); if (WebGLMetaMask.Instance.GetActiveChainId() == chainId) { return; } - await SwitchNetwork(chainId); + await SwitchNetworkInternal(chainId); } } } - private static async Task SwitchNetwork(BigInteger chainId) + private static async Task SwitchNetworkInternal(BigInteger chainId) { var switchEthereumChainParameter = new SwitchEthereumChainParameter { ChainId = new HexBigInteger(chainId) }; var rpcRequest = new RpcRequest { Method = "wallet_switchEthereumChain", Params = new object[] { switchEthereumChainParameter } }; _ = await WebGLMetaMask.Instance.RequestAsync(rpcRequest); } - private static async Task AddNetwork(BigInteger chainId) + private static async Task AddNetworkInternal(BigInteger chainId) { ThirdwebDebug.Log($"Fetching chain data for chainId {chainId}..."); var twChainData = await Utils.GetChainMetadata(_client, chainId) ?? throw new Exception($"Chain data for chainId {chainId} could not be fetched."); diff --git a/Assets/Thirdweb/Runtime/Unity/Wallets/Core/WalletConnectWallet.cs b/Assets/Thirdweb/Runtime/Unity/Wallets/Core/WalletConnectWallet.cs index c1ee4e09a..44c096b98 100644 --- a/Assets/Thirdweb/Runtime/Unity/Wallets/Core/WalletConnectWallet.cs +++ b/Assets/Thirdweb/Runtime/Unity/Wallets/Core/WalletConnectWallet.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Numerics; -using System.Text; using System.Threading.Tasks; using Nethereum.ABI.EIP712; using WalletConnectSharp.Sign.Models; @@ -19,7 +18,7 @@ namespace Thirdweb.Unity public class WalletConnectWallet : IThirdwebWallet { public ThirdwebClient Client => _client; - + public string WalletId => "walletconnect"; public ThirdwebAccountType AccountType => ThirdwebAccountType.ExternalAccount; protected ThirdwebClient _client; @@ -36,7 +35,7 @@ protected WalletConnectWallet(ThirdwebClient client) _client = client; } - public async static Task Create(ThirdwebClient client, BigInteger initialChainId, BigInteger[] supportedChains) + public async static Task Create(ThirdwebClient client, BigInteger initialChainId, BigInteger[] supportedChains, string[] includedWalletIds) { var eip155ChainsSupported = new string[] { }; if (supportedChains != null) @@ -45,6 +44,7 @@ public async static Task Create(ThirdwebClient client, BigI _exception = null; _isConnected = false; _supportedChains = eip155ChainsSupported; + _includedWalletIds = includedWalletIds; if (WalletConnect.Instance != null && WalletConnect.Instance.IsConnected) { @@ -60,6 +60,7 @@ public async static Task Create(ThirdwebClient client, BigI } CreateNewSession(eip155ChainsSupported); + WalletConnectModal.ModalClosed += OnModalClosed; while (!WalletConnect.Instance.IsConnected && _exception == null) { @@ -68,6 +69,7 @@ public async static Task Create(ThirdwebClient client, BigI if (_exception != null) { + WalletConnectModal.ModalClosed -= OnModalClosed; throw _exception; } else @@ -90,10 +92,12 @@ public async static Task Create(ThirdwebClient client, BigI _walletConnectService = new WalletConnectServiceCore(WalletConnect.Instance.SignClient); } - return new WalletConnectWallet(client); + var wcw = new WalletConnectWallet(client); + Utils.TrackConnection(wcw); + return wcw; } - public async Task EnsureCorrectNetwork(BigInteger chainId) + public async Task SwitchNetwork(BigInteger chainId) { var currentChainId = WalletConnect.Instance.ActiveChainId; if (currentChainId == $"eip155:{chainId}") @@ -125,6 +129,12 @@ public async Task EnsureCorrectNetwork(BigInteger chainId) await WalletConnect.Instance.SignClient.AddressProvider.SetDefaultChainIdAsync($"eip155:{chainId}"); } + [Obsolete("Use IThirdwebWallet.SwitchNetwork instead.")] + public Task EnsureCorrectNetwork(BigInteger chainId) + { + return SwitchNetwork(chainId); + } + #region IThirdwebWallet public Task GetAddress() @@ -254,6 +264,38 @@ public Task RecoverAddressFromTypedDataV4(T data, TypedData< throw new NotImplementedException(); } + public Task> LinkAccount( + IThirdwebWallet walletToLink, + string otp = null, + bool? isMobile = null, + Action browserOpenAction = null, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + BigInteger? chainId = null, + string jwt = null, + string payload = null, + string defaultSessionIdOverride = null, + List forceWalletIds = null + ) + { + throw new InvalidOperationException("LinkAccount is not supported by external wallets."); + } + + public Task> GetLinkedAccounts() + { + throw new InvalidOperationException("GetLinkedAccounts is not supported by external wallets."); + } + + public Task> UnlinkAccount(LinkedAccount accountToUnlink) + { + throw new InvalidOperationException("UnlinkAccount is not supported by external wallets."); + } + + public Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute) + { + throw new InvalidOperationException("SignAuthorization is not supported by external wallets."); + } + #endregion #region UI @@ -276,13 +318,7 @@ protected static void CreateNewSession(string[] supportedChains) }; var connectOptions = new ConnectOptions { OptionalNamespaces = optionalNamespaces, }; - - // Open modal WalletConnectModal.Open(new WalletConnectModalOptions { ConnectOptions = connectOptions, IncludedWalletIds = _includedWalletIds }); - WalletConnectModal.ModalClosed += (sender, e) => - { - _exception = new Exception("WalletConnect modal was closed."); - }; } catch (Exception e) { @@ -290,6 +326,14 @@ protected static void CreateNewSession(string[] supportedChains) } } + protected static void OnModalClosed(object sender, EventArgs e) + { + if (!WalletConnect.Instance.IsConnected) + { + _exception = new Exception("WalletConnect modal was closed."); + } + } + #endregion private void SessionRequestDeeplink() @@ -299,25 +343,5 @@ private void SessionRequestDeeplink() WalletConnect.Instance.Linker.OpenSessionRequestDeepLinkAfterMessageFromSession(activeSessionTopic); #endif } - - public Task> LinkAccount( - IThirdwebWallet walletToLink, - string otp = null, - bool? isMobile = null, - Action browserOpenAction = null, - string mobileRedirectScheme = "thirdweb://", - IThirdwebBrowser browser = null, - BigInteger? chainId = null, - string jwt = null, - string payload = null - ) - { - throw new InvalidOperationException("LinkAccount is not supported by external wallets."); - } - - public Task> GetLinkedAccounts() - { - throw new InvalidOperationException("GetLinkedAccounts is not supported by external wallets."); - } } } diff --git a/Assets/Thirdweb/Runtime/Unity/Wallets/Core/WebGLMetaMask.cs b/Assets/Thirdweb/Runtime/Unity/Wallets/Core/WebGLMetaMask.cs index 63652ddeb..30bf892f2 100644 --- a/Assets/Thirdweb/Runtime/Unity/Wallets/Core/WebGLMetaMask.cs +++ b/Assets/Thirdweb/Runtime/Unity/Wallets/Core/WebGLMetaMask.cs @@ -67,8 +67,9 @@ private void Awake() } } - public async Task EnableEthereumAsync() + public async Task EnableEthereumAsync(BigInteger chainId) { + _activeChainId = chainId; _enableEthereumTaskCompletionSource = new TaskCompletionSource(); #if UNITY_WEBGL && !UNITY_EDITOR diff --git a/Assets/Thirdweb/Runtime/Unity/WebGL/WebGLCopyBuffer.jslib b/Assets/Thirdweb/Runtime/Unity/WebGL/WebGLCopyBuffer.jslib new file mode 100644 index 000000000..c88c0a1b4 --- /dev/null +++ b/Assets/Thirdweb/Runtime/Unity/WebGL/WebGLCopyBuffer.jslib @@ -0,0 +1,31 @@ +mergeInto(LibraryManager.library, { + ThirdwebCopyBuffer: function (textPtr) { + var text = UTF8ToString(textPtr); + + if (navigator.clipboard && navigator.clipboard.writeText) { + navigator.clipboard + .writeText(text) + .then(function () { + console.log("Copied to clipboard:", text); + }) + .catch(function (err) { + console.warn("Failed to copy text with navigator.clipboard:", err); + fallbackCopyText(text); + }); + } else { + fallbackCopyText(text); + } + + function fallbackCopyText(textToCopy) { + var input = document.createElement("textarea"); + input.value = textToCopy; + input.style.position = "absolute"; + input.style.left = "-9999px"; + document.body.appendChild(input); + input.select(); + document.execCommand("copy"); + document.body.removeChild(input); + console.log("Copied to clipboard using fallback:", textToCopy); + } + }, +}); diff --git a/Assets/Thirdweb/Runtime/Unity/WebGL/WebGLCopyBuffer.jslib.meta b/Assets/Thirdweb/Runtime/Unity/WebGL/WebGLCopyBuffer.jslib.meta new file mode 100644 index 000000000..0fc1c9026 --- /dev/null +++ b/Assets/Thirdweb/Runtime/Unity/WebGL/WebGLCopyBuffer.jslib.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 19e03b44cf3b7044a8f39760c8340904 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + WebGL: WebGL + second: + enabled: 1 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 775ddea92..bb7a825e4 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -141,7 +141,7 @@ PlayerSettings: loadStoreDebugModeEnabled: 0 visionOSBundleVersion: 1.0 tvOSBundleVersion: 1.0 - bundleVersion: 5.9.0 + bundleVersion: 5.26.0 preloadedAssets: [] metroInputSource: 0 wsaTransparentSwapchain: 0 diff --git a/README.md b/README.md index e309daaf6..9ebc34d25 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,17 @@ ![Thirdweb Unity SDK](https://github.com/thirdweb-dev/unity-sdk/assets/43042585/0eb16b66-317b-462b-9eb1-9425c0929c96) -[Unity Documentation](https://portal.thirdweb.com/unity/v5) -[.NET Documentation](https://portal.thirdweb.com/dotnet) +

+ All-In-One Cross-Platform Blockchain Unity SDK for Browser, Standalone, Mobile and Server Targets. +

+ +

+ + Unity Documentation + + + .NET Documentation + +

# Technical Demo @@ -9,18 +19,34 @@ Experience our multichain game demo leveraging In-App Wallets and Account Abstra ![image](https://github.com/thirdweb-dev/unity-sdk/assets/43042585/171198b2-83e7-4c8a-951b-79126dd47abb) +# Features + +This SDK provides a Unity-first integration of all [thirdweb](https://thirdweb.com) functionality, including but not limited to: + +- Support for all target platforms, Unity 2022 & Unity 6. +- First party support for [In-App Wallets](https://portal.thirdweb.com/connect/wallet/overview) (Guest, Email, Phone, Socials, Custom Auth+). +- First party support for [Account Abstraction](https://portal.thirdweb.com/connect/account-abstraction/overview) (Both EIP-4337 & zkSync Native AA). +- Instant connection to any chain with RPC Edge integration. +- Integrated IPFS upload/download. +- Create blockchain-powered agents with Thirdweb [Nebula](https://thirdweb.com/nebula). +- Easy to extend or wrap. +- High level contract extensions for interacting with common standards and thirdweb contract standards. +- Automatic ABI resolution. +- Build on top of thirdweb's [.NET SDK](https://portal.thirdweb.com/dotnet) - unity package updates are typically updates to a single DLL/a file or two. +- Get started in 5 minutes with a simple [ThirdwebManager](https://portal.thirdweb.com/unity/v5/thirdwebmanager) prefab. + # Supported Platforms & Wallets -**Build games for WebGL, Desktop, and Mobile using 1000+ supported chains, with various login options!** +**Build games for Web, Standalone, and Mobile using 2000+ supported chains, with various login options!** -| Wallet Provider | WebGL | Desktop | Mobile | -| ----------------------------------------- | :---: | :-----: | :----: | -| **In-App Wallet** (Email, Phone, Socials, Custom) | ✔️ | ✔️ | ✔️ | -| **Ecosystem Wallet** (IAW w/ partner permissions) | ✔️ | ✔️ | ✔️ | -| **Private Key Wallet** (Guest Mode) | ✔️ | ✔️ | ✔️ | -| **Wallet Connect Wallet** (400+ Wallets) | ✔️ | ✔️ | ✔️ | -| **MetaMask Wallet** (Browser Extension) | ✔️ | — | — | -| **Smart Wallet** (Account Abstraction) | ✔️ | ✔️ | ✔️ | +| Wallet Provider | Web | Standalone | Mobile | +| ------------------------------------------------------------ | :---: | :-----: | :----: | +| **In-App Wallet** (Guest, Email, Phone, Socials, Backend, Custom) | ✔️ | ✔️ | ✔️ | +| **Ecosystem Wallet** (IAW w/ partner permissions) | ✔️ | ✔️ | ✔️ | +| **Private Key Wallet** (Ephemereal, good for testing) | ✔️ | ✔️ | ✔️ | +| **Wallet Connect Wallet** (400+ Wallets) | ✔️ | ✔️ | ✔️ | +| **MetaMask Wallet** (Browser Extension) | ✔️ | — | — | +| **Smart Wallet** (Account Abstraction: 4337, ZkSync Native, 7702) | ✔️ | ✔️ | ✔️ | ✔️ Supported   ❌ Not Supported   — Not Applicable @@ -30,62 +56,24 @@ Experience our multichain game demo leveraging In-App Wallets and Account Abstra 2. **Explore:** Try out `Scene_Playground` to explore functionality and get onboarded. 3. **Learn:** Explore the [Unity v5 SDK Docs](https://portal.thirdweb.com/unity/v5) and the [.NET SDK Docs](https://portal.thirdweb.com/dotnet) to find a full API reference. -**Notes:** +## Miscellaneous -- Tested on Unity 2021.3+, 2022.3+, Unity 6 Preview. We recommend using 2022 LTS. -- Newtonsoft and EDM4U are included utilities; deselect if already installed to avoid conflicts. +- Recommended Unity Editor Version: 2022.3+ (LTS) +- Newtonsoft.Json and EDM4U are included utilities; deselect when importing if already installed to avoid conflicts. - If using .NET Framework and encountering `HttpUtility` errors, create `csc.rsp` with `-r:System.Web.dll` under `Assets`. -- Use version control and test removing duplicate DLLs if conflicts arise. - -# Build Instructions - -## General - -- **Build Settings:** Use `Smaller (faster) Builds` / `Shorter Build Time`. -- **Player Settings:** Use IL2CPP over Mono when available. -- **Stripping Level:** Set `Managed Stripping Level` to `Minimal` (`Player Settings` > `Other Settings` > `Optimization`). (Generally not a hard requirement unless using WalletConnect as a wallet provider option.) -- **Strip Engine Code:** Make sure this is turned off. - -## WebGL - -- **WebGL Template:** None enforced, feel free to customize! -- **Compression Format:** Set to `Disabled` (`Player Settings` > `Publishing Settings`) for final builds. -- **Testing WebGL Social Login Locally:** Host the build or run it locally with `Cross-Origin-Opener-Policy` set to `same-origin-allow-popups`. - -Example setup for testing In-App or Ecosystem Wallet Social Login locally (no longer required with Unity 6 Web, can use Build & Run): - -```javascript -// YourWebGLOutputFolder/server.js -const express = require("express"); -const app = express(); -const port = 8000; - -app.use((req, res, next) => { - res.header("Cross-Origin-Opener-Policy", "same-origin-allow-popups"); - next(); -}); - -app.use(express.static(".")); -app.listen(port, () => - console.log(`Server running on http://localhost:${port}`) -); - -// run it with `node server.js` -``` - -No action needed for hosted builds. - -## Mobile +- Use version control and test removing duplicate DLLs if conflicts arise. Our SDK generally works with most versions of the few dependencies we do include. +- To use your own WalletConnect Project ID, edit `Assets/Thirdweb/Plugins/WalletConnectUnity/Resources/WalletConnectProjectConfig.asset`. -- **EDM4U:** Comes with the package, resolves dependencies at runtime. Use `Force Resolve` from `Assets` > `External Dependency Manager` > `Android Resolver`. -- **Redirect Schemes:** Set custom schemes matching your bundle ID in `Plugins/AndroidManifest.xml` or equivalent to ensure OAuth redirects. +## Additional Resources -# Migration from v4 +- [Documentation](https://portal.thirdweb.com/unity/v5) +- [Templates](https://thirdweb.com/templates) +- [Website](https://thirdweb.com) -See https://portal.thirdweb.com/unity/v5/migration-guide +## Support -# Need Help? +For help or feedback, please [visit our support site](https://thirdweb.com/support) -For any questions or support, visit our [Support Portal](https://thirdweb.com/support). +## Security -Thank you for trying out the Thirdweb Unity SDK! +If you believe you have found a security vulnerability in any of our packages, we kindly ask you not to open a public issue; and to disclose this to us by emailing `security@thirdweb.com`.