From 75366dcbd78c0c52e4c9b6133adfe40b9cbd8247 Mon Sep 17 00:00:00 2001 From: Andrei Dabija Date: Thu, 24 Oct 2024 16:36:44 +0300 Subject: [PATCH] Updated to v7.10.3 --- CHANGELOG.md | 7 + Editor/GA_Menu.cs | 2 +- Editor/GA_SettingsInspector.cs | 685 ++---------- Editor/GA_SignUp.cs | 1182 ++------------------ Runtime/Scripts/Events/GA_SpecialEvents.cs | 2 +- Runtime/Scripts/Setup/Settings.cs | 2 +- Runtime/iOS/libGameAnalytics.a | Bin 3954752 -> 3954152 bytes package.json | 2 +- 8 files changed, 200 insertions(+), 1682 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2325a60..6fa3ad6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ Changelog --------- +**7.10.3** +* removed user sign-up form +* updated GATool links +* updated documentation links +* updated login requests +* update game and organization requests + **7.10.2** * fixed legacy FPS warning if events were sent before sdk was initialized:fixed webgl string marshaling bug diff --git a/Editor/GA_Menu.cs b/Editor/GA_Menu.cs index 9375091..d700d01 100644 --- a/Editor/GA_Menu.cs +++ b/Editor/GA_Menu.cs @@ -20,7 +20,7 @@ static void SetupAndTour () signup.maxSize = new Vector2(640, 600); signup.minSize = new Vector2(640, 600); - signup.titleContent = new GUIContent ("GameAnalytics - Sign up for FREE"); + signup.titleContent = new GUIContent ("GameAnalytics - Setup Guide"); signup.ShowUtility (); signup.Opened(); diff --git a/Editor/GA_SettingsInspector.cs b/Editor/GA_SettingsInspector.cs index 0a7c3df..efadaff 100644 --- a/Editor/GA_SettingsInspector.cs +++ b/Editor/GA_SettingsInspector.cs @@ -51,7 +51,7 @@ public class GA_SettingsInspector : UnityEditor.Editor private GUIContent _usePlayerSettingsBunldeVersionForBuild = new GUIContent("Send Build number (iOS) and Version* (Android) as build number", "The SDK will automatically fetch the build number on iOS and the version* number on Android and send it as the GameAnalytics build number."); #endif //private GUIContent _sendExampleToMyGame = new GUIContent("Get Example Game Data", "If enabled data collected while playing the example tutorial game will be sent to your game (using your game key and secret key). Otherwise data will be sent to a premade GA test game, to prevent it from polluting your data."); - private GUIContent _account = new GUIContent("Account", "This tab allows you to easily create a GameAnalytics account. You can also login to automatically retrieve your Game Key and Secret Key."); + private GUIContent _account = new GUIContent("Account", "This tab allows you to login and automatically retrieve your Game Key and Secret Key."); private GUIContent _setup = new GUIContent("Setup", "This tab shows general options which are relevant for a wide variety of messages sent to GameAnalytics."); private GUIContent _advanced = new GUIContent("Advanced", "This tab shows advanced and misc. options for the GameAnalytics SDK."); private GUIContent _customDimensions01 = new GUIContent("Custom Dimensions 01", "List of custom dimensions 01."); @@ -99,13 +99,32 @@ public class GA_SettingsInspector : UnityEditor.Editor private const string _unityToken = "KKy7MQNc2TEUOeK0EMtR"; - private const string _gaUrl = "https://userapi.gameanalytics.com/ext/v1/"; + private const string _gaUrl = "https://platform.gameanalytics.com/ext/v1/"; + + private const string _gaToolUrl = "https://tool.gameanalytics.com"; + + private const string _gaForgotPasswordUrl = _gaToolUrl + "/forgot-password"; + + private const string _gaSettingsUrl = _gaToolUrl + "/game/{0}/settings/general"; + + private const string _gaOverviewUrl = _gaToolUrl + "/game/{0}/overview"; + + private const string _gaLoginUrl = _gaToolUrl + "/login?"; + + private const string _gaSignUpUrl = _gaToolUrl + "/signup"; + + private const string _gaSupportUrl = "http://support.gameanalytics.com/"; private const int MaxNumberOfDimensions = 20; private int selectedPlatformIndex = 0; private string[] availablePlatforms; + private const int MAJOR_V = 0; + private const int MINOR_V = 1; + private const int PATCH_V = 2; + private const int ALL_V = 3; + void OnEnable() { GameAnalyticsSDK.Setup.Settings ga = target as GameAnalyticsSDK.Setup.Settings; @@ -245,11 +264,11 @@ public override void OnInspectorGUI() GUILayout.EndHorizontal(); GUILayout.EndVertical(); - DrawLinkButton(_homeIcon, GUI.skin.label, "https://go.gameanalytics.com/login", GUILayout.Width(24), GUILayout.Height(24)); + DrawLinkButton(_homeIcon, GUI.skin.label, _gaLoginUrl, GUILayout.Width(24), GUILayout.Height(24)); DrawLinkButton(_questionIcon, GUI.skin.label, "http://support.gameanalytics.com/", GUILayout.Width(24), GUILayout.Height(24)); - DrawButton(_instrumentIcon, GUI.skin.label, OpenSignUpSwitchToGuideStep, GUILayout.Width(24), GUILayout.Height(24)); + DrawLinkButton(_instrumentIcon, GUI.skin.label, _gaSignUpUrl, GUILayout.Width(24), GUILayout.Height(24)); GUILayout.EndHorizontal(); @@ -430,7 +449,7 @@ public override void OnInspectorGUI() GUILayout.BeginVertical(); GUILayout.Space(8); - DrawLinkButton("Forgot password?", EditorStyles.label, "https://go.gameanalytics.com/login?showreset&email=" + ga.EmailGA, GUILayout.Width(105)); + DrawLinkButton("Forgot password?", EditorStyles.label, _gaForgotPasswordUrl, GUILayout.Width(105)); EditorGUIUtility.AddCursorRect(GUILayoutUtility.GetLastRect(), MouseCursor.Link); GUILayout.EndVertical(); GUILayout.EndHorizontal(); @@ -568,7 +587,7 @@ public override void OnInspectorGUI() GUILayout.Space(14); if (GUILayout.Button("Forgot password?", EditorStyles.label, GUILayout.Width(105))) { - Application.OpenURL("https://go.gameanalytics.com/login?showreset&email=" + ga.EmailGA); + Application.OpenURL(_gaForgotPasswordUrl); } EditorGUIUtility.AddCursorRect(GUILayoutUtility.GetLastRect(), MouseCursor.Link); GUILayout.EndVertical(); @@ -580,29 +599,6 @@ public override void OnInspectorGUI() GUILayout.Space(16); - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - if (GUILayout.Button("Sign up", new GUILayoutOption[] { - GUILayout.Width(130), - GUILayout.Height(40) - })) - { - GA_SignUp signup = ScriptableObject.CreateInstance(); - signup.maxSize = new Vector2(640, 600); - signup.minSize = new Vector2(640, 600); - signup.titleContent = new GUIContent("GameAnalytics - Sign up for FREE"); - signup.ShowUtility(); - signup.Opened(); - } - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.Space(16); - - Splitter(new Color(0.35f, 0.35f, 0.35f)); - - GUILayout.Space(16); - GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("I want to fill in my game keys manually", EditorStyles.label, GUILayout.Width(207))) @@ -664,7 +660,7 @@ public override void OnInspectorGUI() Rect tmpRect = GUILayoutUtility.GetLastRect(); if (GUI.Button(new Rect(tmpRect.x + 5, tmpRect.y + tmpRect.height - 25, 80, 20), "Learn more")) { - Application.OpenURL("https://github.com/GameAnalytics/GA-SDK-UNITY/wiki/Settings#setup"); + Application.OpenURL("https://docs.gameanalytics.com/integrations/sdk/unity"); } } #endregion // Setup help @@ -692,17 +688,6 @@ public override void OnInspectorGUI() EditorGUILayout.Space(); } - if (GUILayout.Button("Add game")) - { - GA_SignUp signup = ScriptableObject.CreateInstance(); - signup.maxSize = new Vector2(640, 600); - signup.minSize = new Vector2(640, 600); - signup.TourStep = 1; - signup.titleContent = new GUIContent("GameAnalytics - Sign up for FREE"); - signup.ShowUtility(); - signup.Opened(); - } - GUILayout.BeginHorizontal(); //GUILayout.Label("", GUILayout.Width(7)); GUILayout.Label("Status", GUILayout.Width(63)); @@ -926,22 +911,22 @@ public override void OnInspectorGUI() { if (string.IsNullOrEmpty(ga.TokenGA)) { - Application.OpenURL("https://go.gameanalytics.com/game/" + ga.SelectedPlatformGameID[i] + "/initialize"); + Application.OpenURL(String.Format(_gaOverviewUrl, ga.SelectedPlatformGameID[i])); } else { - Application.OpenURL("https://go.gameanalytics.com/login?token=" + ga.TokenGA + "&exp=" + ga.ExpireTime + "&goto=/game/" + ga.SelectedPlatformGameID[i] + "/initialize"); + Application.OpenURL(_gaLoginUrl); } } if (GUILayout.Button("Game Settings")) { if (string.IsNullOrEmpty(ga.TokenGA)) { - Application.OpenURL("https://go.gameanalytics.com/game/" + ga.SelectedPlatformGameID[i] + "/settings"); + Application.OpenURL(String.Format(_gaSettingsUrl, ga.SelectedPlatformGameID[i])); } else { - Application.OpenURL("https://go.gameanalytics.com/login?token=" + ga.TokenGA + "&exp=" + ga.ExpireTime + "&goto=/game/" + ga.SelectedPlatformGameID[i] + "/settings"); + Application.OpenURL(_gaLoginUrl); } } GUILayout.EndHorizontal(); @@ -978,28 +963,6 @@ public override void OnInspectorGUI() this.selectedPlatformIndex = 0; } -#if UNITY_IOS || UNITY_TVOS - - EditorGUILayout.Space(); - - GUILayout.BeginHorizontal(); - GUILayout.Label("", GUILayout.Width(-18)); - EditorGUILayout.HelpBox("PLEASE NOTICE: Xcode needs to be configured to work with GameAnalytics. Click here to learn more about the build process for iOS.", MessageType.Info); - - if(GUI.Button(GUILayoutUtility.GetLastRect(), "", GUIStyle.none)) - { - Application.OpenURL("https://github.com/GameAnalytics/GA-SDK-UNITY/wiki/Configure%20XCode"); - } - EditorGUIUtility.AddCursorRect(GUILayoutUtility.GetLastRect(), MouseCursor.Link); - - GUILayout.EndHorizontal(); - -#elif UNITY_ANDROID || UNITY_STANDALONE || UNITY_WEBGL || UNITY_WSA || UNITY_WP_8_1 || UNITY_TIZEN || UNITY_SAMSUNGTV - - // Do nothing - -#else - EditorGUILayout.Space(); GUILayout.BeginHorizontal(); @@ -1014,8 +977,6 @@ public override void OnInspectorGUI() GUILayout.EndHorizontal(); -#endif - EditorGUILayout.Space(); EditorGUILayout.Space(); EditorGUILayout.Space(); @@ -1060,7 +1021,7 @@ public override void OnInspectorGUI() Rect tmpRect = GUILayoutUtility.GetLastRect(); if (GUI.Button(new Rect(tmpRect.x + 5, tmpRect.y + tmpRect.height - 25, 80, 20), "Learn more")) { - Application.OpenURL("https://github.com/GameAnalytics/GA-SDK-UNITY/wiki/Settings#custom-dimensions"); + Application.OpenURL("https://docs.gameanalytics.com/integrations/sdk/unity/advanced-setup#custom-dimensions"); } } @@ -1249,7 +1210,7 @@ public override void OnInspectorGUI() Rect tmpRect = GUILayoutUtility.GetLastRect(); if (GUI.Button(new Rect(tmpRect.x + 5, tmpRect.y + tmpRect.height - 25, 80, 20), "Learn more")) { - Application.OpenURL("https://github.com/GameAnalytics/GA-SDK-UNITY/wiki/Settings#resource-types"); + Application.OpenURL("https://docs.gameanalytics.com/integrations/sdk/unity/advanced-setup#resource-types"); } } @@ -1396,7 +1357,7 @@ public override void OnInspectorGUI() Rect tmpRect = GUILayoutUtility.GetLastRect(); if (GUI.Button(new Rect(tmpRect.x + 5, tmpRect.y + tmpRect.height - 25, 80, 20), "Learn more")) { - Application.OpenURL("https://github.com/GameAnalytics/GA-SDK-UNITY/wiki/Settings#advanced"); + Application.OpenURL("https://docs.gameanalytics.com/integrations/sdk/unity/advanced-setup#advanced-settings"); } } @@ -1497,7 +1458,7 @@ public override void OnInspectorGUI() Rect tmpRect = GUILayoutUtility.GetLastRect(); if (GUI.Button(new Rect(tmpRect.x + 5, tmpRect.y + tmpRect.height - 25, 80, 20), "Learn more")) { - Application.OpenURL("https://github.com/GameAnalytics/GA-SDK-UNITY/wiki/Settings#debug-settings"); + Application.OpenURL("https://docs.gameanalytics.com/integrations/sdk/unity/advanced-setup#advanced-settings"); } } @@ -1683,142 +1644,6 @@ private MessageType ConvertMessageType(GameAnalyticsSDK.Setup.Settings.MessageTy } } - public static void SignupUser(GameAnalyticsSDK.Setup.Settings ga, GA_SignUp signup) - { - Hashtable jsonTable = new Hashtable(); - jsonTable["email"] = ga.EmailGA; - jsonTable["password"] = ga.PasswordGA; - jsonTable["password_confirm"] = signup.PasswordConfirm; - jsonTable["first_name"] = signup.FirstName; - jsonTable["last_name"] = signup.LastName; - jsonTable["studio_name"] = ga.StudioName; - jsonTable["org_name"] = ga.OrganizationName; - jsonTable["org_identifier"] = ga.OrganizationIdentifier; - jsonTable["email_opt_out"] = signup.EmailOptIn; - jsonTable["accept_terms"] = signup.AcceptedTerms; - - byte[] data = System.Text.Encoding.UTF8.GetBytes(GA_MiniJSON.Serialize(jsonTable)); - -#if UNITY_2017_1_OR_NEWER - UnityWebRequest www = new UnityWebRequest(_gaUrl + "user", UnityWebRequest.kHttpVerbPOST); - UploadHandlerRaw uH = new UploadHandlerRaw(data) - { - contentType = "application/json" - }; - www.uploadHandler = uH; - www.downloadHandler = new DownloadHandlerBuffer(); - Dictionary headers = GA_EditorUtilities.WWWHeaders(); - foreach (KeyValuePair entry in headers) - { - www.SetRequestHeader(entry.Key, entry.Value); - } -#else - WWW www = new WWW(_gaUrl + "user", data, GA_EditorUtilities.WWWHeaders()); -#endif - - GA_ContinuationManager.StartCoroutine(SignupUserFrontend(www, ga, signup), () => www.isDone); - } - -#if UNITY_2017_1_OR_NEWER - private static IEnumerator SignupUserFrontend(UnityWebRequest www, GameAnalyticsSDK.Setup.Settings ga, GA_SignUp signup) -#else - private static IEnumerator SignupUserFrontend(WWW www, Settings ga, GA_SignUp signup) -#endif - { -#if UNITY_2017_1_OR_NEWER - -#if UNITY_2017_2_OR_NEWER - yield return www.SendWebRequest(); -#else - yield return www.Send(); -#endif - while (!www.isDone) - yield return null; -#else - yield return www; -#endif - - try - { - IDictionary returnParam = null; - string error = ""; -#if UNITY_2017_1_OR_NEWER - string text = www.downloadHandler.text; -#else - string text = www.text; -#endif - if (!string.IsNullOrEmpty(text)) - { - returnParam = GA_MiniJSON.Deserialize(text) as IDictionary; - if (returnParam.ContainsKey("errors")) - { - IList errorList = returnParam["errors"] as IList; - if (errorList != null && errorList.Count > 0) - { - IDictionary errors = errorList[0] as IDictionary; - if (errors.ContainsKey("msg")) - { - error = errors["msg"].ToString(); - } - } - } - } - -#if UNITY_2020_1_OR_NEWER - if (!(www.result == UnityWebRequest.Result.ConnectionError || www.result == UnityWebRequest.Result.ProtocolError)) -#elif UNITY_2017_1_OR_NEWER - if (!(www.isNetworkError || www.isHttpError)) -#else - if (string.IsNullOrEmpty(www.error)) -#endif - { - if (!String.IsNullOrEmpty(error)) - { - Debug.LogError(error); - SetLoginStatus("Failed to sign up.", ga); - signup.SignUpFailed(); - } - else if (returnParam != null) - { - IList resultList = returnParam["results"] as IList; - IDictionary results = resultList[0] as IDictionary; - ga.TokenGA = results["token"].ToString(); - ga.ExpireTime = results["exp"].ToString(); - - ga.JustSignedUp = true; - - //ga.SignUpOpen = false; - - ga.Organizations = null; - SetLoginStatus("Signed up. Getting data.", ga); - - GetUserData(ga); - signup.SignUpComplete(); - } - } -#if UNITY_5_4_OR_NEWER - else if(www.responseCode == 301 || www.responseCode == 404 || www.responseCode == 410) - { - Debug.LogError("Failed to sign up. GameAnalytics request not successful. API was changed. Please update your SDK to the latest version: " + www.error + " " + error); - SetLoginStatus("Failed to sign up. GameAnalytics request not successful. API was changed. Please update your SDK to the latest version.", ga); - signup.SignUpFailed(); - } -#endif - else - { - Debug.LogError("Failed to sign up: " + www.error + " " + error); - SetLoginStatus("Failed to sign up.", ga); - signup.SignUpFailed(); - } - } - catch - { - Debug.LogError("Failed to sign up"); - SetLoginStatus("Failed to sign up.", ga); - signup.SignUpFailed(); - } - } - private static void LoginUser(GameAnalyticsSDK.Setup.Settings ga) { Hashtable jsonTable = new Hashtable(); @@ -1827,7 +1652,6 @@ private static void LoginUser(GameAnalyticsSDK.Setup.Settings ga) byte[] data = System.Text.Encoding.UTF8.GetBytes(GA_MiniJSON.Serialize(jsonTable)); -#if UNITY_2017_1_OR_NEWER UnityWebRequest www = new UnityWebRequest(_gaUrl + "token", UnityWebRequest.kHttpVerbPOST); UploadHandlerRaw uH = new UploadHandlerRaw(data) { @@ -1841,44 +1665,31 @@ private static void LoginUser(GameAnalyticsSDK.Setup.Settings ga) { www.SetRequestHeader(entry.Key, entry.Value); } -#else - WWW www = new WWW(_gaUrl + "token", data, GA_EditorUtilities.WWWHeaders()); -#endif + GA_ContinuationManager.StartCoroutine(LoginUserFrontend(www, ga), () => www.isDone); } -#if UNITY_2017_1_OR_NEWER + private static IEnumerator LoginUserFrontend(UnityWebRequest www, GameAnalyticsSDK.Setup.Settings ga) -#else - private static IEnumerator LoginUserFrontend(WWW www, Settings ga) -#endif { -#if UNITY_2017_1_OR_NEWER -#if UNITY_2017_2_OR_NEWER + yield return www.SendWebRequest(); -#else - yield return www.Send(); -#endif + while (!www.isDone) yield return null; -#else - yield return www; -#endif try { string error = ""; IDictionary returnParam = null; -#if UNITY_2017_1_OR_NEWER + string text = www.downloadHandler.text; -#else - string text = www.text; -#endif + if (!string.IsNullOrEmpty(text)) { returnParam = GA_MiniJSON.Deserialize(text) as IDictionary; - if (returnParam.ContainsKey("errors")) + if (returnParam != null && returnParam.ContainsKey("errors")) { IList errorList = returnParam["errors"] as IList; if (errorList != null && errorList.Count > 0) @@ -1902,7 +1713,6 @@ private static IEnumerator LoginUserFrontend(WWW www, Settings ga) { if (!String.IsNullOrEmpty(error)) { - Debug.LogError(error); SetLoginStatus("Failed to login.", ga); } else if (returnParam != null) @@ -1910,75 +1720,58 @@ private static IEnumerator LoginUserFrontend(WWW www, Settings ga) IList resultList = returnParam["results"] as IList; IDictionary results = resultList[0] as IDictionary; ga.TokenGA = results["token"].ToString(); - ga.ExpireTime = results["exp"].ToString(); SetLoginStatus("Logged in. Getting data.", ga); GetUserData(ga); } } -#if UNITY_5_4_OR_NEWER else if (www.responseCode == 301 || www.responseCode == 404 || www.responseCode == 410) { Debug.LogError("Failed to login. GameAnalytics request not successful. API was changed. Please update your SDK to the latest version: " + www.error + " " + error); SetLoginStatus("Failed to login. GameAnalytics request not successful. API was changed. Please update your SDK to the latest version.", ga); } -#endif else { Debug.LogError("Failed to login: " + www.error + " " + error); SetLoginStatus("Failed to login.", ga); } } - catch + catch(Exception e) { - Debug.LogError("Failed to login"); + Debug.LogError("Failed to login:" + e.ToString()); + Debug.LogError(e.StackTrace); SetLoginStatus("Failed to login.", ga); } } private static void GetUserData(GameAnalyticsSDK.Setup.Settings ga) { -#if UNITY_2017_1_OR_NEWER UnityWebRequest www = UnityWebRequest.Get(_gaUrl + "user"); Dictionary headers = GA_EditorUtilities.WWWHeadersWithAuthorization(ga.TokenGA); foreach (KeyValuePair entry in headers) { www.SetRequestHeader(entry.Key, entry.Value); } -#else - WWW www = new WWW(_gaUrl + "user", null, GA_EditorUtilities.WWWHeadersWithAuthorization(ga.TokenGA)); -#endif + GA_ContinuationManager.StartCoroutine(GetUserDataFrontend(www, ga), () => www.isDone); } -#if UNITY_2017_1_OR_NEWER + private static IEnumerator GetUserDataFrontend(UnityWebRequest www, GameAnalyticsSDK.Setup.Settings ga) -#else - private static IEnumerator GetUserDataFrontend(WWW www, Settings ga) -#endif { -#if UNITY_2017_1_OR_NEWER -#if UNITY_2017_2_OR_NEWER yield return www.SendWebRequest(); -#else - yield return www.Send(); -#endif + while (!www.isDone) yield return null; -#else - yield return www; -#endif try { IDictionary returnParam = null; string error = ""; -#if UNITY_2017_1_OR_NEWER + string text = www.downloadHandler.text; -#else - string text = www.text; -#endif + if (!string.IsNullOrEmpty(text)) { returnParam = GA_MiniJSON.Deserialize(text) as IDictionary; @@ -2000,8 +1793,6 @@ private static IEnumerator GetUserDataFrontend(WWW www, Settings ga) if (!(www.result == UnityWebRequest.Result.ConnectionError || www.result == UnityWebRequest.Result.ProtocolError)) #elif UNITY_2017_1_OR_NEWER if (!(www.isNetworkError || www.isHttpError)) -#else - if (string.IsNullOrEmpty(www.error)) #endif { if (!String.IsNullOrEmpty(error)) @@ -2095,323 +1886,6 @@ private static IEnumerator GetUserDataFrontend(WWW www, Settings ga) } } - public static void CreateGame(GameAnalyticsSDK.Setup.Settings ga, GA_SignUp signup, int organizationIndex, int studioIndex, string gameTitle, string googlePlayPublicKey, RuntimePlatform platform, AppFiguresGame appFiguresGame) - { - Hashtable jsonTable = new Hashtable(); - - if (appFiguresGame != null) - { - jsonTable["title"] = gameTitle; - jsonTable["store_id"] = appFiguresGame.AppID; - jsonTable["store"] = appFiguresGame.Store; - jsonTable["googleplay_key"] = string.IsNullOrEmpty(googlePlayPublicKey) ? null : googlePlayPublicKey; - } - else - { - jsonTable["title"] = gameTitle; - jsonTable["store_id"] = null; - jsonTable["store"] = null; - jsonTable["googleplay_key"] = string.IsNullOrEmpty(googlePlayPublicKey) ? null : googlePlayPublicKey; - } - - byte[] data = System.Text.Encoding.UTF8.GetBytes(GA_MiniJSON.Serialize(jsonTable)); - - string url = _gaUrl + "studios/" + ga.Organizations[organizationIndex].Studios[studioIndex].ID + "/games"; -#if UNITY_2017_1_OR_NEWER - UnityWebRequest www = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPOST); - UploadHandlerRaw uH = new UploadHandlerRaw(data) - { - contentType = "application/json" - }; - www.uploadHandler = uH; - www.downloadHandler = new DownloadHandlerBuffer(); - Dictionary headers = GA_EditorUtilities.WWWHeadersWithAuthorization(ga.TokenGA); - foreach (KeyValuePair entry in headers) - { - www.SetRequestHeader(entry.Key, entry.Value); - } -#else - WWW www = new WWW(url, data, GA_EditorUtilities.WWWHeadersWithAuthorization(ga.TokenGA)); -#endif - GA_ContinuationManager.StartCoroutine(CreateGameFrontend(www, ga, signup, platform, appFiguresGame), () => www.isDone); - } - -#if UNITY_2017_1_OR_NEWER - private static IEnumerator CreateGameFrontend(UnityWebRequest www, GameAnalyticsSDK.Setup.Settings ga, GA_SignUp signup, RuntimePlatform platform, AppFiguresGame appFiguresGame) -#else - private static IEnumerator CreateGameFrontend(WWW www, Settings ga, GA_SignUp signup, RuntimePlatform platform, AppFiguresGame appFiguresGame) -#endif - { -#if UNITY_2017_1_OR_NEWER -#if UNITY_2017_2_OR_NEWER - yield return www.SendWebRequest(); -#else - yield return www.Send(); -#endif - while (!www.isDone) - yield return null; -#else - yield return www; -#endif - - try - { - IDictionary returnParam = null; - string error = ""; -#if UNITY_2017_1_OR_NEWER - string text = www.downloadHandler.text; -#else - string text = www.text; -#endif - if (!string.IsNullOrEmpty(text)) - { - returnParam = GA_MiniJSON.Deserialize(text) as IDictionary; - if (returnParam.ContainsKey("errors")) - { - IList errorList = returnParam["errors"] as IList; - if (errorList != null && errorList.Count > 0) - { - IDictionary errors = errorList[0] as IDictionary; - if (errors.ContainsKey("msg")) - { - error = errors["msg"].ToString(); - } - } - } - } - -#if UNITY_2020_1_OR_NEWER - if (!(www.result == UnityWebRequest.Result.ConnectionError || www.result == UnityWebRequest.Result.ProtocolError)) -#elif UNITY_2017_1_OR_NEWER - if (!(www.isNetworkError || www.isHttpError)) -#else - if (string.IsNullOrEmpty(www.error)) -#endif - { - if (!String.IsNullOrEmpty(error)) - { - Debug.LogError(error); - SetLoginStatus("Failed to create game.", ga); - signup.CreateGameFailed(); - } - else - { - ga.LastCreatedGamePlatform = platform; - GetUserData(ga); - signup.CreateGameComplete(); - } - } -#if UNITY_5_4_OR_NEWER - else if (www.responseCode == 301 || www.responseCode == 404 || www.responseCode == 410) - { - Debug.LogError("Failed to create game. GameAnalytics request not successful. API was changed. Please update your SDK to the latest version: " + www.error + " " + error); - SetLoginStatus("Failed to create game. GameAnalytics request not successful. API was changed. Please update your SDK to the latest version.", ga); - } -#endif - else - { - Debug.LogError("Failed to create game: " + www.error + " " + error); - SetLoginStatus("Failed to create game.", ga); - signup.CreateGameFailed(); - } - } - catch - { - Debug.LogError("Failed to create game"); - SetLoginStatus("Failed to create game.", ga); - signup.CreateGameFailed(); - } - } - - public static void GetAppFigures(GameAnalyticsSDK.Setup.Settings ga, GA_SignUp signup) - { -#if UNITY_2017_1_OR_NEWER - UnityWebRequest www = UnityWebRequest.Get(_gaUrl + "apps/search?query=" + UnityWebRequest.EscapeURL(ga.GameName)); - Dictionary headers = GA_EditorUtilities.WWWHeadersWithAuthorization(ga.TokenGA); - foreach (KeyValuePair pair in headers) - { - www.SetRequestHeader(pair.Key, pair.Value); - } - GA_ContinuationManager.StartCoroutine(GetAppFiguresFrontend(www, ga, signup, ga.GameName), () => www.isDone); -#else - WWW www = new WWW(_gaUrl + "apps/search?query=" + WWW.EscapeURL(ga.GameName), null, GA_EditorUtilities.WWWHeadersWithAuthorization(ga.TokenGA)); - GA_ContinuationManager.StartCoroutine(GetAppFiguresFrontend(www, ga, signup, ga.GameName), () => www.isDone); -#endif - - if (ga.AmazonIcon == null) - { -#if UNITY_2017_1_OR_NEWER - UnityWebRequest wwwAmazon = UnityWebRequestTexture.GetTexture("http://public.gameanalytics.com/resources/images/sdk_doc/appstore_icons/amazon.png"); - GA_ContinuationManager.StartCoroutine(signup.GetAppStoreIconTexture(wwwAmazon, "amazon_appstore", signup), () => wwwAmazon.isDone); -#else - WWW wwwAmazon = new WWW("http://public.gameanalytics.com/resources/images/sdk_doc/appstore_icons/amazon.png"); - GA_ContinuationManager.StartCoroutine(signup.GetAppStoreIconTexture(wwwAmazon, "amazon_appstore", signup), () => wwwAmazon.isDone); -#endif - } - - if (ga.GooglePlayIcon == null) - { -#if UNITY_2017_1_OR_NEWER - UnityWebRequest wwwGoogle = UnityWebRequestTexture.GetTexture("http://public.gameanalytics.com/resources/images/sdk_doc/appstore_icons/google_play.png"); - GA_ContinuationManager.StartCoroutine(signup.GetAppStoreIconTexture(wwwGoogle, "google_play", signup), () => wwwGoogle.isDone); -#else - WWW wwwGoogle = new WWW("http://public.gameanalytics.com/resources/images/sdk_doc/appstore_icons/google_play.png"); - GA_ContinuationManager.StartCoroutine(signup.GetAppStoreIconTexture(wwwGoogle, "google_play", signup), () => wwwGoogle.isDone); -#endif - } - - if (ga.iosIcon == null) - { -#if UNITY_2017_1_OR_NEWER - UnityWebRequest wwwIos = UnityWebRequestTexture.GetTexture("http://public.gameanalytics.com/resources/images/sdk_doc/appstore_icons/ios.png"); - GA_ContinuationManager.StartCoroutine(signup.GetAppStoreIconTexture(wwwIos, "apple:ios", signup), () => wwwIos.isDone); -#else - WWW wwwIos = new WWW("http://public.gameanalytics.com/resources/images/sdk_doc/appstore_icons/ios.png"); - GA_ContinuationManager.StartCoroutine(signup.GetAppStoreIconTexture(wwwIos, "apple:ios", signup), () => wwwIos.isDone); -#endif - } - - if (ga.macIcon == null) - { -#if UNITY_2017_1_OR_NEWER - UnityWebRequest wwwMac = UnityWebRequestTexture.GetTexture("http://public.gameanalytics.com/resources/images/sdk_doc/appstore_icons/mac.png"); - GA_ContinuationManager.StartCoroutine(signup.GetAppStoreIconTexture(wwwMac, "apple:mac", signup), () => wwwMac.isDone); -#else - WWW wwwMac = new WWW("http://public.gameanalytics.com/resources/images/sdk_doc/appstore_icons/mac.png"); - GA_ContinuationManager.StartCoroutine(signup.GetAppStoreIconTexture(wwwMac, "apple:mac", signup), () => wwwMac.isDone); -#endif - } - - if (ga.windowsPhoneIcon == null) - { -#if UNITY_2017_1_OR_NEWER - UnityWebRequest wwwWindowsPhone = UnityWebRequestTexture.GetTexture("http://public.gameanalytics.com/resources/images/sdk_doc/appstore_icons/windows_phone.png"); - GA_ContinuationManager.StartCoroutine(signup.GetAppStoreIconTexture(wwwWindowsPhone, "windows_phone", signup), () => wwwWindowsPhone.isDone); -#else - WWW wwwWindowsPhone = new WWW("http://public.gameanalytics.com/resources/images/sdk_doc/appstore_icons/windows_phone.png"); - GA_ContinuationManager.StartCoroutine(signup.GetAppStoreIconTexture(wwwWindowsPhone, "windows_phone", signup), () => wwwWindowsPhone.isDone); -#endif - } - } - -#if UNITY_2017_1_OR_NEWER - private static IEnumerator GetAppFiguresFrontend(UnityWebRequest www, GameAnalyticsSDK.Setup.Settings ga, GA_SignUp signup, string gameName) -#else - private static IEnumerator GetAppFiguresFrontend(WWW www, Settings ga, GA_SignUp signup, string gameName) -#endif - { -#if UNITY_2017_1_OR_NEWER -#if UNITY_2017_2_OR_NEWER - yield return www.SendWebRequest(); -#else - yield return www.Send(); -#endif - while (!www.isDone) - yield return null; -#else - yield return www; -#endif - - try - { - IDictionary returnParam = null; - string error = ""; - string text; -#if UNITY_2017_1_OR_NEWER - text = www.downloadHandler.text; -#else - text = www.text; -#endif - if (!string.IsNullOrEmpty(text)) - { - returnParam = GA_MiniJSON.Deserialize(text) as IDictionary; - if (returnParam.ContainsKey("errors")) - { - IList errorList = returnParam["errors"] as IList; - if (errorList != null && errorList.Count > 0) - { - IDictionary errors = errorList[0] as IDictionary; - if (errors.ContainsKey("msg")) - { - error = errors["msg"].ToString(); - } - } - } - } - -#if UNITY_2020_1_OR_NEWER - if (!(www.result == UnityWebRequest.Result.ConnectionError || www.result == UnityWebRequest.Result.ProtocolError)) -#elif UNITY_2017_1_OR_NEWER - if (!(www.isNetworkError || www.isHttpError)) -#else - if (string.IsNullOrEmpty(www.error)) -#endif - { - if (!String.IsNullOrEmpty(error)) - { - Debug.LogError(error); - SetLoginStatus("Failed to get app.", ga); - } - else if (returnParam != null) - { - IList resultList = returnParam["results"] as IList; - - List appFiguresGames = new List(); - for (int s = 0; s < resultList.Count; s++) - { - IDictionary result = resultList[s] as IDictionary; - - string name = result["title"].ToString(); - string appID = result["store_id"].ToString(); - string store = result["store"].ToString(); - string developer = result["developer"].ToString(); - string iconUrl = result["image"].ToString(); - - if (store.Equals("apple") || store.Equals("google_play") || store.Equals("amazon_appstore")) - { - appFiguresGames.Add(new AppFiguresGame(name, appID, store, developer, iconUrl, signup)); - } - } - - signup.AppFigComplete(gameName, appFiguresGames); - } - } - else - { - // expired tokens / not signed in -#if UNITY_2017_1_OR_NEWER - if (www.responseCode == 401) -#else - if (www.responseHeaders["status"] != null && www.responseHeaders["status"].Contains("401")) -#endif - { - Selection.objects = new UnityEngine.Object[] { AssetDatabase.LoadAssetAtPath("Assets/Resources/GameAnalytics/Settings.asset", typeof(GameAnalyticsSDK.Setup.Settings)) }; - ga.CurrentInspectorState = GameAnalyticsSDK.Setup.Settings.InspectorStates.Account; - string message = "Please sign-in and try again to search for your game in the stores."; - SetLoginStatus(message, ga); - Debug.LogError(message); - } -#if UNITY_5_4_OR_NEWER - else if (www.responseCode == 301 || www.responseCode == 404 || www.responseCode == 410) - { - Debug.LogError("Failed to find app. GameAnalytics request not successful. API was changed. Please update your SDK to the latest version: " + www.error + " " + error); - SetLoginStatus("Failed to find app. GameAnalytics request not successful. API was changed. Please update your SDK to the latest version.", ga); - } -#endif - else - { - Debug.LogError("Failed to find app: " + www.error + " " + text); - SetLoginStatus("Failed to find app.", ga); - } - } - } - catch (Exception e) - { - Debug.LogError("Failed to find app: " + e.ToString() + ", " + e.StackTrace); - SetLoginStatus("Failed to find app.", ga); - } - } - private static void SelectOrganization(int index, GameAnalyticsSDK.Setup.Settings ga, int platform) { ga.SelectedOrganization[platform] = index; @@ -2491,11 +1965,8 @@ public static void CheckForUpdates() } GameAnalyticsSDK.Setup.Settings.CheckingForUpdates = true; -#if UNITY_2017_1_OR_NEWER + UnityWebRequest www = UnityWebRequest.Get("https://s3.amazonaws.com/public.gameanalytics.com/sdk_status/current.json"); -#else - WWW www = new WWW("https://s3.amazonaws.com/public.gameanalytics.com/sdk_status/current.json"); -#endif GA_ContinuationManager.StartCoroutine(CheckForUpdatesCoroutine(www), () => www.isDone); } @@ -2509,23 +1980,12 @@ private static void GetChangeLogsAndShowUpdateWindow(string newVersion) GA_ContinuationManager.StartCoroutine(GetChangeLogsAndShowUpdateWindowCoroutine(www, newVersion), () => www.isDone); } -#if UNITY_2017_1_OR_NEWER private static IEnumerator CheckForUpdatesCoroutine(UnityWebRequest www) -#else - private static IEnumerator CheckForUpdatesCoroutine(WWW www) -#endif { -#if UNITY_2017_1_OR_NEWER -#if UNITY_2017_2_OR_NEWER yield return www.SendWebRequest(); -#else - yield return www.Send(); -#endif + while (!www.isDone) yield return null; -#else - yield return www; -#endif try { @@ -2718,6 +2178,7 @@ private static string PlatformToString(RuntimePlatform platform) // [majorVersion].[minorVersion].[patchnumber] static bool IsNewVersion(string newVersion, string currentVersion) { + int[] newVersionInts = GetVersionIntegersFromString(newVersion); int[] currentVersionInts = GetVersionIntegersFromString(currentVersion); @@ -2727,27 +2188,27 @@ static bool IsNewVersion(string newVersion, string currentVersion) } // compare majorVersion - if(newVersionInts[0] > currentVersionInts[0]) + if(newVersionInts[MAJOR_V] > currentVersionInts[MAJOR_V]) { return true; } - else if(newVersionInts[0] < currentVersionInts[0]) + else if(newVersionInts[MAJOR_V] < currentVersionInts[MAJOR_V]) { return false; } // compare minorVersion (majorVersion is unchanged) - if(newVersionInts[1] > currentVersionInts[1]) + if(newVersionInts[MINOR_V] > currentVersionInts[MINOR_V]) { return true; } - else if(newVersionInts[1] < currentVersionInts[1]) + else if(newVersionInts[MINOR_V] < currentVersionInts[MINOR_V]) { return false; } // compare patchnumber (majorVersion, minorVersion is unchanged) - if(newVersionInts[2] > currentVersionInts[2]) + if(newVersionInts[PATCH_V] > currentVersionInts[PATCH_V]) { return true; } @@ -2761,18 +2222,18 @@ static bool IsNewVersion(string newVersion, string currentVersion) static int[] GetVersionIntegersFromString(string versionString) { string[] versionNumbers = versionString.Split('.'); - if(versionNumbers.Length != 3) + if(versionNumbers.Length != ALL_V) { return null; } // container for validated version integers - int[] validatedVersionNumbers = new int[3]; + int[] validatedVersionNumbers = new int[ALL_V]; // verify int parsing - bool isIntMajorVersion = int.TryParse(versionNumbers[0], out validatedVersionNumbers[0]); - bool isIntMinorVersion = int.TryParse(versionNumbers[1], out validatedVersionNumbers[1]); - bool isIntPatchnumber = int.TryParse(versionNumbers[2], out validatedVersionNumbers[2]); + bool isIntMajorVersion = int.TryParse(versionNumbers[MAJOR_V], out validatedVersionNumbers[MAJOR_V]); + bool isIntMinorVersion = int.TryParse(versionNumbers[MINOR_V], out validatedVersionNumbers[MINOR_V]); + bool isIntPatchnumber = int.TryParse(versionNumbers[PATCH_V], out validatedVersionNumbers[PATCH_V]); if(isIntMajorVersion && isIntMinorVersion && isIntPatchnumber) { @@ -2784,33 +2245,19 @@ static int[] GetVersionIntegersFromString(string versionString) } } -#region Button actions +#region Helper functions - private void OpenSignUp() + private static void OpenSignUp() { - GameAnalyticsSDK.Setup.Settings ga = target as GameAnalyticsSDK.Setup.Settings; - ga.IntroScreen = false; - ga.CurrentInspectorState = GameAnalyticsSDK.Setup.Settings.InspectorStates.Account; - ga.SignUpOpen = true; - - GA_SignUp signup = ScriptableObject.CreateInstance(); - signup.maxSize = new Vector2(640, 600); - signup.minSize = new Vector2(640, 600); - signup.titleContent = new GUIContent("GameAnalytics - Sign up for FREE"); - signup.ShowUtility(); - signup.Opened(); + Application.OpenURL(_gaSignUpUrl); } -#endregion // Button actions - -#region Helper functions - private static void OpenSignUpSwitchToGuideStep() { GA_SignUp signup = ScriptableObject.CreateInstance(); signup.maxSize = new Vector2(640, 600); signup.minSize = new Vector2(640, 600); - signup.titleContent = new GUIContent("GameAnalytics - Sign up for FREE"); + signup.titleContent = new GUIContent("GameAnalytics - Setup Guide"); signup.ShowUtility(); signup.Opened(); diff --git a/Editor/GA_SignUp.cs b/Editor/GA_SignUp.cs index 5ed1f24..01ce981 100644 --- a/Editor/GA_SignUp.cs +++ b/Editor/GA_SignUp.cs @@ -3,885 +3,87 @@ using UnityEditor; using System.Collections.Generic; using GameAnalyticsSDK.Setup; -#if UNITY_2017_1_OR_NEWER -using UnityEngine.Networking; -#endif - -namespace GameAnalyticsSDK.Editor -{ - public class GA_SignUp : EditorWindow - { - private GUIContent _firstNameLabel = new GUIContent("First name", "Your first name."); - private GUIContent _lastNameLabel = new GUIContent("Last name", "Your last name (surname)."); - private GUIContent _studioNameLabel = new GUIContent("Studio name", "Your studio's name. You can add more studios and games on the GameAnalytics website."); - private GUIContent _organizationNameLabel = new GUIContent("Organization name", "Your organization's name. You can add more studios and games under your organization on the GameAnalytics website."); - private GUIContent _organizationIdentifierLabel = new GUIContent("Organization identifier", "Your organization's identifier to be used in url. Must be unique. Can only contain lowercase letters, digits and hyphens"); - private GUIContent _gameNameLabel = new GUIContent("Game name", "Your game's name. You can add more studies and games on the GameAnalytics website."); - private GUIContent _passwordConfirmLabel = new GUIContent("Confirm password", "Your GameAnalytics user account password."); - private GUIContent _emailOptInLabel = new GUIContent("Subscribe to release updates, news and tips and tricks.", "If enabled GameAnalytics may send you news about updates, cool tips and tricks, and other news to help you get the most out of our service."); - private GUIContent _termsLabel = new GUIContent("I have read and agree with your"); - private GUIContent _emailLabel = new GUIContent("Email", "Your GameAnalytics user account email."); - private GUIContent _passwordLabel = new GUIContent("Password", "Your GameAnalytics user account password. Must be at least 8 characters in length."); - //private GUIContent _studiosLabel = new GUIContent("Studio", "Studios tied to your GameAnalytics user account."); - //private GUIContent _gamesLabel = new GUIContent("Game", "Games tied to the selected GameAnalytics studio."); - - public int TourStep = 0; - public bool AcceptedTerms = false; - public string FirstName = ""; - public string LastName = ""; - public string PasswordConfirm = ""; - public bool EmailOptIn = true; - - private Vector2 _appScrollPos; - private string _appFigName; - - private const int INPUT_WIDTH = 230; - - private List _appFiguresGames; - private AppFiguresGame _appFiguresGame; - - private static GA_SignUp _instance; - - private bool _signUpInProgress = false; - private bool _createGameInProgress = false; - private string _googlePlayPublicKey = ""; - private RuntimePlatform _selectedPlatform; - private int _selectedOrganization; - private int _selectedStudio; - - private enum StringType - { - Label, - TextBox, - Link - - } - - private struct StringWithType - { - public string Text; - public StringType Type; - public string Link; - } - - public void Opened() - { - if (_instance == null) - { - _instance = this; - } - else - { - Close(); - } - } - - void OnDisable() - { - if (_instance == this) - { - _instance = null; - } - } - - void OnGUI() - { - switch (TourStep) - { - #region sign up - case 0: // sign up - - GUILayout.Space(20); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label(GameAnalytics.SettingsGA.UserIcon, new GUILayoutOption[] { - GUILayout.Width(40), - GUILayout.MaxHeight(40) - }); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.Space(5); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label("Create your account", EditorStyles.whiteLargeLabel); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - - // first name - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label(_firstNameLabel, GUILayout.Width(INPUT_WIDTH)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - FirstName = EditorGUILayout.TextField("", FirstName, GUILayout.Width(INPUT_WIDTH)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - - // last name - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label(_lastNameLabel, GUILayout.Width(INPUT_WIDTH)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - LastName = EditorGUILayout.TextField("", LastName, GUILayout.Width(INPUT_WIDTH)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - - // e-mail - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label(_emailLabel, GUILayout.Width(INPUT_WIDTH)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GameAnalytics.SettingsGA.EmailGA = EditorGUILayout.TextField("", GameAnalytics.SettingsGA.EmailGA, GUILayout.Width(INPUT_WIDTH)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - - // password - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label(_passwordLabel, GUILayout.Width(INPUT_WIDTH)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GameAnalytics.SettingsGA.PasswordGA = EditorGUILayout.PasswordField("", GameAnalytics.SettingsGA.PasswordGA, GUILayout.Width(INPUT_WIDTH)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - - // confirm password - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label(_passwordConfirmLabel, GUILayout.Width(INPUT_WIDTH)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - PasswordConfirm = EditorGUILayout.PasswordField("", PasswordConfirm, GUILayout.Width(INPUT_WIDTH)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - - // studio name - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label(_studioNameLabel, GUILayout.Width(INPUT_WIDTH)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GameAnalytics.SettingsGA.StudioName = EditorGUILayout.TextField("", GameAnalytics.SettingsGA.StudioName, GUILayout.Width(INPUT_WIDTH)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - - // organization name - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label(_organizationNameLabel, GUILayout.Width(INPUT_WIDTH)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GameAnalytics.SettingsGA.OrganizationName = EditorGUILayout.TextField("", GameAnalytics.SettingsGA.OrganizationName, GUILayout.Width(INPUT_WIDTH)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - - // organization identifier - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label(_organizationIdentifierLabel, GUILayout.Width(INPUT_WIDTH)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GameAnalytics.SettingsGA.OrganizationIdentifier = EditorGUILayout.TextField("", GameAnalytics.SettingsGA.OrganizationIdentifier, GUILayout.Width(INPUT_WIDTH)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - - // email opt in - - EditorGUILayout.Space(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - EmailOptIn = EditorGUILayout.Toggle("", EmailOptIn, GUILayout.Width(15)); - GUILayout.Label(_emailOptInLabel); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - - // terms of service - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - AcceptedTerms = EditorGUILayout.Toggle("", AcceptedTerms, GUILayout.Width(15)); - GUILayout.Label(_termsLabel, GUILayout.Width(171)); - GUILayout.Space(-5); - GUILayout.BeginVertical(); - GUILayout.Space(2); - if (GUILayout.Button("Terms of Service", EditorStyles.boldLabel, GUILayout.Width(105))) - { - Application.OpenURL("http://www.gameanalytics.com/terms"); - } - EditorGUIUtility.AddCursorRect(GUILayoutUtility.GetLastRect(), MouseCursor.Link); - GUILayout.EndVertical(); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - - // create account button - - EditorGUILayout.Space(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUI.enabled = !_signUpInProgress; - if (AcceptedTerms) - { - if (GUILayout.Button("Create account", new GUILayoutOption[] { - GUILayout.Width(200), - GUILayout.MaxHeight(30) - })) - { - _signUpInProgress = true; - GA_SettingsInspector.SignupUser(GameAnalytics.SettingsGA, this); - } - } - else - { - EditorGUILayout.HelpBox("Please read and agree with our terms before you can create an account.", MessageType.Warning); - } - - GUI.enabled = true; - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - break; - #endregion // sign up - - #region add your game - case 1: // add your game - - GUILayout.Space(20); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label(GameAnalytics.SettingsGA.GameIcon, new GUILayoutOption[] { - GUILayout.Width(40), - GUILayout.MaxHeight(40) - }); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.Space(5); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label("Add your game", EditorStyles.whiteLargeLabel); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label("You can quickly add your game by searching the app store."); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - // game name - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label(_gameNameLabel, GUILayout.Width(500)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - int tmpFontSize = GUI.skin.textField.fontSize; - Vector2 tmpOffset = GUI.skin.textField.contentOffset; - GUI.skin.textField.fontSize = 12; - GUI.skin.textField.contentOffset = new Vector2(6, 6); - GameAnalytics.SettingsGA.GameName = EditorGUILayout.TextField("", GameAnalytics.SettingsGA.GameName, new GUILayoutOption[] { - GUILayout.Width(300), - GUILayout.Height(30) - }); - GUI.skin.textField.fontSize = tmpFontSize; - GUI.skin.textField.contentOffset = tmpOffset; - if (GUILayout.Button("Find your game", new GUILayoutOption[] { - GUILayout.Width(200), - GUILayout.MaxHeight(30) - })) - { - GA_SettingsInspector.GetAppFigures(GameAnalytics.SettingsGA, this); - } - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - GA_SettingsInspector.Splitter(new Color(0.35f, 0.35f, 0.35f), 1, 30); - - if (_appFiguresGames != null && _appFiguresGames.Count > 0) - { - EditorGUILayout.Space(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label("'" + _appFigName + "' matched " + _appFiguresGames.Count + " titles.", EditorStyles.boldLabel); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - _appScrollPos = GUILayout.BeginScrollView(_appScrollPos, GUI.skin.box, GUILayout.Width(571)); - - for (int i = 0; i < _appFiguresGames.Count; i++) - { - GUILayout.BeginHorizontal(); - if (_appFiguresGames[i].Icon != null) - { - GUILayout.Label(_appFiguresGames[i].Icon, new GUILayoutOption[] { - GUILayout.Width(32), - GUILayout.Height(32) - }); - } - else - { - GUILayout.Label("", new GUILayoutOption[] { - GUILayout.Width(32), - GUILayout.Height(32) - }); - } - Rect lastRect = GUILayoutUtility.GetLastRect(); - Vector2 tmpOffsetLabel = GUI.skin.label.contentOffset; - GUI.skin.label.contentOffset = new Vector2(0, 9); - GUILayout.Label(_appFiguresGames[i].Name, GUILayout.Width(200)); - GUILayout.Label(_appFiguresGames[i].Developer, GUILayout.Width(200)); - - PaintAppStoreIcon(_appFiguresGames[i].Store); - - GUI.skin.label.contentOffset = tmpOffsetLabel; - GUILayout.EndHorizontal(); - GA_SettingsInspector.Splitter(new Color(0.35f, 0.35f, 0.35f), 1, 10); - - Rect appFigRect = new Rect(lastRect.x - 5, lastRect.y - 5, lastRect.width + 520, lastRect.height + 10); - if (GUI.Button(appFigRect, "", GUIStyle.none)) - { - _appFiguresGame = _appFiguresGames[i]; - TourStep = 3; - } - EditorGUIUtility.AddCursorRect(appFigRect, MouseCursor.Link); - } - - GUILayout.EndScrollView(); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - } - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label("If your game is still in development or not in the app store, please add it manually."); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - // create new game button - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - if (GUILayout.Button("Create new game", new GUILayoutOption[] { - GUILayout.Width(200), - GUILayout.Height(30) - })) - { - TourStep = 2; - } - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - break; - #endregion // add your game - - #region create new game - case 2: // create new game - - GUILayout.Space(20); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label(GameAnalytics.SettingsGA.GameIcon, new GUILayoutOption[] { - GUILayout.Width(40), - GUILayout.MaxHeight(40) - }); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.Space(5); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label("Create new game", EditorStyles.whiteLargeLabel); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - // game name - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label(_gameNameLabel, GUILayout.Width(300)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - int tmpFontSize2 = GUI.skin.textField.fontSize; - Vector2 tmpOffset2 = GUI.skin.textField.contentOffset; - GUI.skin.textField.fontSize = 12; - GUI.skin.textField.contentOffset = new Vector2(5, 5); - GameAnalytics.SettingsGA.GameName = EditorGUILayout.TextField("", GameAnalytics.SettingsGA.GameName, new GUILayoutOption[] { - GUILayout.Width(300), - GUILayout.Height(30) - }); - GUI.skin.textField.fontSize = tmpFontSize2; - GUI.skin.textField.contentOffset = tmpOffset2; - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - this._selectedOrganization = EditorGUILayout.Popup("", this._selectedOrganization, Organization.GetOrganizationNames(GameAnalytics.SettingsGA.Organizations, false), GUILayout.Width(200)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - this._selectedStudio = EditorGUILayout.Popup("", this._selectedStudio, this._selectedOrganization > 0 ? Studio.GetStudioNames(GameAnalytics.SettingsGA.Organizations[this._selectedOrganization - 1].Studios, false) : new string[0], GUILayout.Width(200)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GameAnalyticsSDK.Setup.Settings settings = CreateInstance(); - this._selectedPlatform = (RuntimePlatform)EditorGUILayout.Popup("", (int)this._selectedPlatform, settings.GetAvailablePlatforms(), GUILayout.Width(200)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - if (this._selectedPlatform == RuntimePlatform.Android) - { - GUILayout.BeginHorizontal(); - EditorGUILayout.HelpBox("PLEASE NOTICE: If you want to validate your Android in-app purchase please enter your Google Play License key (public key). Click here to learn more about the Google Play License key.", MessageType.Info); - - if (GUI.Button(GUILayoutUtility.GetLastRect(), "", GUIStyle.none)) - { - //Application.OpenURL("https://github.com/GameAnalytics/GA-SDK-UNITY/wiki/Configure%20XCode"); - } - EditorGUIUtility.AddCursorRect(GUILayoutUtility.GetLastRect(), MouseCursor.Link); - - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - GUILayout.BeginHorizontal(); - GUILayout.Label("Google Play License key", GUILayout.Width(150)); - this._googlePlayPublicKey = GUILayout.TextField(this._googlePlayPublicKey); - GUILayout.EndHorizontal(); - } - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - // create game button - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUI.enabled = !_createGameInProgress; - if (GUILayout.Button("Create game", new GUILayoutOption[] { - GUILayout.Width(200), - GUILayout.MaxHeight(30) - })) - { - _createGameInProgress = true; - GA_SettingsInspector.CreateGame(GameAnalytics.SettingsGA, this, this._selectedOrganization, this._selectedStudio, GameAnalytics.SettingsGA.GameName, this._googlePlayPublicKey, this._selectedPlatform, null); - } - GUI.enabled = true; - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - GA_SettingsInspector.Splitter(new Color(0.35f, 0.35f, 0.35f), 1, 30); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label("Go back to "); - Rect r1 = GUILayoutUtility.GetLastRect(); - GUILayout.Space(-5); - GUILayout.BeginVertical(); - GUILayout.Space(2); - GUILayout.Label("Add your game", EditorStyles.boldLabel); - GUILayout.EndVertical(); - Rect r2 = GUILayoutUtility.GetLastRect(); - Rect r3 = new Rect(r1.x, r1.y, r1.width + r2.width, r2.height); - if (GUI.Button(r3, "", GUIStyle.none)) - { - TourStep = 1; - } - EditorGUIUtility.AddCursorRect(r3, MouseCursor.Link); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - break; - #endregion // create new game - - #region app figures add game - case 3: // app figures add game - - GUILayout.Space(20); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label(GameAnalytics.SettingsGA.GameIcon, new GUILayoutOption[] { - GUILayout.Width(40), - GUILayout.MaxHeight(40) - }); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.Space(5); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label("Is this your game?", EditorStyles.whiteLargeLabel); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label("Please confirm that this is the game you want to add."); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - // game name - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - - if (_appFiguresGame.Icon != null) - { - GUILayout.Label(_appFiguresGame.Icon, new GUILayoutOption[] { - GUILayout.Width(100), - GUILayout.Height(100) - }); - } - else - { - GUILayout.Label("", new GUILayoutOption[] { - GUILayout.Width(100), - GUILayout.Height(100) - }); - } - GUILayout.Label("", GUILayout.Width(25)); - GUILayout.BeginVertical(); - GUILayout.Label(_appFiguresGame.Name, EditorStyles.whiteLargeLabel, GUILayout.Width(200)); - GUILayout.Label(_appFiguresGame.Developer, GUILayout.Width(200)); - GUILayout.Label("", GUILayout.Height(20)); - PaintAppStoreIcon(_appFiguresGame.Store); - GUILayout.EndVertical(); - - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - if (_appFiguresGame.Store.Equals("google_play")) - { - GUILayout.BeginHorizontal(); - EditorGUILayout.HelpBox("PLEASE NOTICE: If you want to validate your Android in-app purchase please enter your Google Play License key (public key). Click here to learn more about the Google Play License key.", MessageType.Info); - - if (GUI.Button(GUILayoutUtility.GetLastRect(), "", GUIStyle.none)) - { - //Application.OpenURL("https://github.com/GameAnalytics/GA-SDK-UNITY/wiki/Configure%20XCode"); - } - EditorGUIUtility.AddCursorRect(GUILayoutUtility.GetLastRect(), MouseCursor.Link); - - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - GUILayout.BeginHorizontal(); - GUILayout.Label("Google Play License key", GUILayout.Width(150)); - this._googlePlayPublicKey = GUILayout.TextField(this._googlePlayPublicKey); - GUILayout.EndHorizontal(); - } - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - this._selectedOrganization = EditorGUILayout.Popup("", this._selectedOrganization, Organization.GetOrganizationNames(GameAnalytics.SettingsGA.Organizations, false), GUILayout.Width(200)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - this._selectedStudio = EditorGUILayout.Popup("", this._selectedStudio, this._selectedOrganization > 0 ? Studio.GetStudioNames(GameAnalytics.SettingsGA.Organizations[this._selectedOrganization - 1].Studios, false) : new string[0], GUILayout.Width(200)); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - // create game button - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUI.enabled = !_createGameInProgress; - if (GUILayout.Button("Add game", new GUILayoutOption[] { - GUILayout.Width(200), - GUILayout.MaxHeight(30) - })) - { - _createGameInProgress = true; - this._selectedPlatform = _appFiguresGame.Store.Equals("google_play") || _appFiguresGame.Store.Equals("amazon_appstore") ? RuntimePlatform.Android : RuntimePlatform.IPhonePlayer; - GA_SettingsInspector.CreateGame(GameAnalytics.SettingsGA, this, this._selectedOrganization, this._selectedStudio, _appFiguresGame.Name, this._googlePlayPublicKey, this._selectedPlatform, _appFiguresGame); - } - GUI.enabled = true; - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label("Go back to "); - Rect r21 = GUILayoutUtility.GetLastRect(); - GUILayout.Space(-5); - GUILayout.BeginVertical(); - GUILayout.Space(2); - GUILayout.Label("results", EditorStyles.boldLabel); - GUILayout.EndVertical(); - Rect r22 = GUILayoutUtility.GetLastRect(); - Rect r23 = new Rect(r21.x, r21.y, r21.width + r22.width, r22.height); - if (GUI.Button(r23, "", GUIStyle.none)) - { - TourStep = 1; - } - EditorGUIUtility.AddCursorRect(r23, MouseCursor.Link); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - GA_SettingsInspector.Splitter(new Color(0.35f, 0.35f, 0.35f), 1, 30); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label("If your game is still in development or not in the app store, please add it manually."); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - EditorGUILayout.Space(); - EditorGUILayout.Space(); - EditorGUILayout.Space(); - - // create new game button - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - if (GUILayout.Button("Create new game", new GUILayoutOption[] { - GUILayout.Width(200), - GUILayout.MaxHeight(30) - })) - { - TourStep = 2; - } - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - break; - #endregion // app figures add game - - #region game created - case 4: - - GUILayout.Space(20); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label(GameAnalytics.SettingsGA.Logo, new GUILayoutOption[] { - GUILayout.Width(40), - GUILayout.Height(40) - }); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.Space(5); +using UnityEngine.Networking; - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label("Congratulations!", EditorStyles.whiteLargeLabel); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); +namespace GameAnalyticsSDK.Editor +{ + public class GA_SignUp : EditorWindow + { + public enum TourSteps + { + SetupGameKeys = 0, + AddObject, + StartTracking, + TrackBusiness, + TrackResources, + TrackProgression, + TrackDesign, + LogErrors, + CustomDimensions, + FinishGuide, + AllSteps - EditorGUILayout.Space(); - EditorGUILayout.Space(); + } - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - GUILayout.Label("Your game has been created successfully."); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); + public TourSteps TourStep = TourSteps.SetupGameKeys; - EditorGUILayout.Space(); - EditorGUILayout.Space(); - EditorGUILayout.Space(); + private bool _showGuidedTour = true; + + private Vector2 _appScrollPos; - GA_SettingsInspector.Splitter(new Color(0.35f, 0.35f, 0.35f), 1, 30); + private const int INPUT_WIDTH = 230; - EditorGUILayout.Space(); - EditorGUILayout.Space(); - EditorGUILayout.Space(); + private static GA_SignUp _instance; - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - TextAnchor tmpLA = GUI.skin.label.alignment; - GUI.skin.label.alignment = TextAnchor.UpperCenter; - GUILayout.Label("We've put together a simple guide to help you instrument GameAnalytics in your game.", GUILayout.MaxWidth(540)); - GUI.skin.label.alignment = tmpLA; - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); + private bool _signUpInProgress = false; + private bool _createGameInProgress = false; + private string _googlePlayPublicKey = ""; + private RuntimePlatform _selectedPlatform; + private int _selectedOrganization; + private int _selectedStudio; - EditorGUILayout.Space(); - EditorGUILayout.Space(); - EditorGUILayout.Space(); - EditorGUILayout.Space(); + private enum StringType + { + Label, + TextBox, + Link - // create game button + } - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - if (GUILayout.Button("Start guide", new GUILayoutOption[] { - GUILayout.Width(200), - GUILayout.MaxHeight(30) - })) - { - TourStep = 5; - } - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); + private struct StringWithType + { + public string Text; + public StringType Type; + public string Link; + } - break; - #endregion // game created + public void Opened() + { + if (_instance == null) + { + _instance = this; + } + else + { + Close(); + } + } - #region guide - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: + void OnDisable() + { + if (_instance == this) + { + _instance = null; + } + } + void OnGUI() + { + if(_showGuidedTour) + { + #region guide gui - int guideStep = TourStep - 4; + TourSteps guideStep = TourStep; GUILayout.Space(20); @@ -923,13 +125,13 @@ void OnGUI() GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); - if (guideStep == 10) + if (guideStep == TourSteps.FinishGuide) GUILayout.Label(GetGuideStepTitle(guideStep), EditorStyles.whiteLargeLabel, GUILayout.Width(464)); else GUILayout.Label(GetGuideStepTitle(guideStep), EditorStyles.whiteLargeLabel, GUILayout.Width(470)); GUILayout.BeginVertical(); GUILayout.Space(7); - if (guideStep == 10) + if (guideStep == TourSteps.FinishGuide) GUILayout.Label("STEP " + (guideStep) + " OF 10", GUILayout.Width(87)); else GUILayout.Label("STEP " + (guideStep) + " OF 10", GUILayout.Width(80)); @@ -991,7 +193,7 @@ void OnGUI() // create game button string buttonText = "Next step"; - if (TourStep == 14) + if (TourStep == TourSteps.FinishGuide) { buttonText = "Done"; } @@ -1003,13 +205,13 @@ void OnGUI() //GUILayout.Space(7); GUI.Label(new Rect(43, 7, 500, 50), GetGuideStepNext(guideStep)); //GUILayout.EndVertical(); - if (guideStep > 1 && GUI.Button(new Rect(454, 0, 30, 30), "<")) + if (guideStep > TourSteps.SetupGameKeys && GUI.Button(new Rect(454, 0, 30, 30), "<")) { TourStep--; } if (GUI.Button(new Rect(489, 0, 100, 30), buttonText)) { - if (TourStep < 14) + if (TourStep < TourSteps.FinishGuide) TourStep++; else Close(); @@ -1018,94 +220,60 @@ void OnGUI() //GUILayout.EndHorizontal(); GUI.EndGroup(); - break; - #endregion // guide + #endregion // guide } } - public void AppFigComplete(string gameName, List appFiguresGames) - { - _appFigName = gameName; - _appFiguresGames = appFiguresGames; - Repaint(); - } - - public void SignUpComplete() - { - _instance.TourStep = 1; - _signUpInProgress = false; - Repaint(); - } - - public void SignUpFailed() - { - _signUpInProgress = false; - Repaint(); - } - - public void CreateGameComplete() - { - TourStep = 4; - _createGameInProgress = false; - Repaint(); - } - - public void CreateGameFailed() - { - _createGameInProgress = false; - Repaint(); - } - public void SwitchToGuideStep() { - TourStep = 5; + TourStep = TourSteps.SetupGameKeys; } - private string GetGuideStepTitle(int step) + private string GetGuideStepTitle(TourSteps step) { switch (step) { - case 1: + case TourSteps.SetupGameKeys: return "1. SETUP GAME KEYS"; - case 2: + case TourSteps.AddObject: return "2. ADD GAMEANALYTICS OBJECT"; - case 3: + case TourSteps.StartTracking: return "3. START TRACKING EVENTS"; - case 4: + case TourSteps.TrackBusiness: return "4. TRACK REAL MONEY TRANSACTIONS"; - case 5: + case TourSteps.TrackResources: return "5. BALANCE VIRTUAL ECONOMY"; - case 6: + case TourSteps.TrackProgression: return "6. TRACK PLAYER PROGRESSION"; - case 7: + case TourSteps.TrackDesign: return "7. USE CUSTOM DESIGN EVENTS"; - case 8: + case TourSteps.LogErrors: return "8. LOG ERROR EVENTS"; - case 9: + case TourSteps.CustomDimensions: return "9. USE CUSTOM DIMENSIONS"; - case 10: + case TourSteps.FinishGuide: return "10. BUILD AND COMPLETE INTEGRATION"; default: return "-"; } } - private StringWithType[] GetGuideStepText(int step) + private StringWithType[] GetGuideStepText(TourSteps step) { switch (step) { - case 1: + case TourSteps.SetupGameKeys: return new StringWithType[] { - new StringWithType { Text = "The unique game and secret key are used to authenticate your game. If you're logged into GameAnalytics, in Settings under the Account tab, choose your studio and game to sync your keys with your Unity project. If you don't have an account, choose Sign up to create your account and game." }, + new StringWithType { Text = "The unique game and secret key are used to authenticate your game. If you're logged into GameAnalytics, in Settings under the Account tab, choose your studio and game to sync your keys with your Unity project. If you don't have an account, visit \"https://tool.gameanalytics.com/signup\" to create your account and game." }, new StringWithType { Text = "You can also input your keys manually in Settings under the Setup tab. The keys can always be found under Game Settings in the webtool." }, new StringWithType { Text = "" }, new StringWithType { - Text = "Click here to learn more about the Game and Secret keys.", + Text = "Click here to create an account.", Type = StringType.Link, - Link = "https://github.com/GameAnalytics/GA-SDK-UNITY/wiki/Settings#setup" + Link = "https://tool.gameanalytics.com/signup" }, }; - case 2: + case TourSteps.AddObject: return new StringWithType[] { new StringWithType { Text = "To use GameAnalytics you need to add the GameAnalytics object to your starting scene. To add this object go to Window/GameAnalytics/Create GameAnalytics Object." }, new StringWithType { Text = "Now you're set up to start tracking data - it's that easy! Out of the box GameAnalytics will give you access to lots of core metrics, such as daily active users (DAU), without implementing any custom events." }, @@ -1113,10 +281,10 @@ private StringWithType[] GetGuideStepText(int step) new StringWithType { Text = "Click here to learn more about the full list of core metrics and dimensions.", Type = StringType.Link, - Link = "http://www.gameanalytics.com/docs/metric-and-dimensions-reference/" + Link = "https://docs.gameanalytics.com/metrics-dimensions" } }; - case 3: + case TourSteps.StartTracking: return new StringWithType[] { new StringWithType { Text = "GameAnalytics supports 5 different types of events: Business, Resource, Progression, Error and Design." }, new StringWithType { Text = "To send an event, remember to include the namespace GameAnalyticsSDK:" }, @@ -1127,7 +295,7 @@ private StringWithType[] GetGuideStepText(int step) new StringWithType { Text = "" }, new StringWithType { Text = "The next steps will guide you through the instrumentation of each of the different event types." }, }; - case 4: + case TourSteps.TrackBusiness: return new StringWithType[] { new StringWithType { Text = "With the Business event, you can include information on the specific type of in-app item purchased, and where in the game the purchase was made. Additionally, the GameAnalytics SDK captures the app store receipt to validate the purchases." }, new StringWithType { Text = "To add a business event call the following function:" }, @@ -1139,10 +307,10 @@ private StringWithType[] GetGuideStepText(int step) new StringWithType { Text = "Click here to learn more about the Business event and purchase validation.", Type = StringType.Link, - Link = "https://github.com/GameAnalytics/GA-SDK-UNITY/wiki/Business%20Event" + Link = "https://docs.gameanalytics.com/integrations/sdk/unity/event-tracking#business-events" } }; - case 5: + case TourSteps.TrackResources: return new StringWithType[] { new StringWithType { Text = "Resources events are used to track your in-game economy. From setting up the event you will be able to see three types of events in the tool. Flow, the total balance from currency spent and rewarded. Sink is all currency spent on items, and lastly source, being all currency rewarded in game." }, new StringWithType { Text = "To add a resource event call the following function:" }, @@ -1155,10 +323,10 @@ private StringWithType[] GetGuideStepText(int step) new StringWithType { Text = "Click here to learn more about the Resource event.", Type = StringType.Link, - Link = "https://github.com/GameAnalytics/GA-SDK-UNITY/wiki/Resource%20Event" + Link = "https://docs.gameanalytics.com/integrations/sdk/unity/event-tracking#resource-events" } }; - case 6: + case TourSteps.TrackProgression: return new StringWithType[] { new StringWithType { Text = "Use this event to track when players start and finish levels in your game. This event follows a 3 tier hierarchy structure (World, Level and Phase) to indicate a player's path or place in the game." }, new StringWithType { Text = "To add a progression event call the following function:" }, @@ -1170,10 +338,10 @@ private StringWithType[] GetGuideStepText(int step) new StringWithType { Text = "Click here to learn more about the Progression event.", Type = StringType.Link, - Link = "https://github.com/GameAnalytics/GA-SDK-UNITY/wiki/Progression%20Event" + Link = "https://docs.gameanalytics.com/integrations/sdk/unity/event-tracking#progression-events" } }; - case 7: + case TourSteps.TrackDesign: return new StringWithType[] { new StringWithType { Text = "Track any other concept in your game using this event type. For example, you could use this event to track GUI elements or tutorial steps. Custom dimensions are not supported on this event type." }, new StringWithType { Text = "To add a design event call the following function:" }, @@ -1185,10 +353,10 @@ private StringWithType[] GetGuideStepText(int step) new StringWithType { Text = "Click here to learn more about the Design event.", Type = StringType.Link, - Link = "https://github.com/GameAnalytics/GA-SDK-UNITY/wiki/Design%20Event" + Link = "https://docs.gameanalytics.com/integrations/sdk/unity/event-tracking#design-events" } }; - case 8: + case TourSteps.LogErrors: return new StringWithType[] { new StringWithType { Text = "You can use the Error event to log errors or warnings that players generate in your game. You can group the events by severity level and attach a message, such as the stack trace." }, new StringWithType { Text = "To add a custom error event call the following function:" }, @@ -1200,10 +368,10 @@ private StringWithType[] GetGuideStepText(int step) new StringWithType { Text = "Click here to learn more about the Error event.", Type = StringType.Link, - Link = "https://github.com/GameAnalytics/GA-SDK-UNITY/wiki/Error%20Event" + Link = "https://docs.gameanalytics.com/integrations/sdk/unity/event-tracking#error-events" } }; - case 9: + case TourSteps.CustomDimensions: return new StringWithType[] { new StringWithType { Text = "Custom Dimensions can be used to filter your data in the GameAnalytics webtool. To add custom dimensions to your events you will first have to create a list of all the allowed values. You can do this in Settings under the Setup tab. Any value which is not defined will be ignored." }, new StringWithType { Text = "For example, to set Custom Dimension 01, call the following function:" }, @@ -1215,10 +383,10 @@ private StringWithType[] GetGuideStepText(int step) new StringWithType { Text = "Click here to learn more about Custom Dimensions.", Type = StringType.Link, - Link = "https://github.com/GameAnalytics/GA-SDK-UNITY/wiki/Set%20Custom%20Dimension" + Link = "https://docs.gameanalytics.com/integrations/sdk/unity/advanced-setup#custom-dimensions" } }; - case 10: + case TourSteps.FinishGuide: return new StringWithType[] { new StringWithType { Text = "You're almost there! To complete the integration and start sending data to GameAnalytics, all you need to do is build and run your game." }, #if UNITY_IOS || UNITY_TVOS || UNITY_ANDROID @@ -1226,34 +394,18 @@ private StringWithType[] GetGuideStepText(int step) #endif new StringWithType { Text = "" }, - #if UNITY_IOS || UNITY_TVOS - - new StringWithType { - Text = "iOS/tvOS", - Type = StringType.Link, - Link = "https://github.com/GameAnalytics/GA-SDK-UNITY/wiki/iOS%20Build" - } - - #elif UNITY_ANDROID - - new StringWithType { - Text = "Android", - Type = StringType.Link, - Link = "https://github.com/GameAnalytics/GA-SDK-UNITY/wiki/Android%20Build" - } - - #elif UNITY_STANDALONE || UNITY_TIZEN || UNITY_WEBGL || UNITY_WINRT + #if UNITY_IOS || UNITY_TVOS || UNITY_STANDALONE || UNITY_TIZEN || UNITY_WEBGL || UNITY_WINRT new StringWithType { Text = "Click here to check online documentation!", Type = StringType.Link, - Link = "https://github.com/GameAnalytics/GA-SDK-UNITY/wiki" + Link = "https://docs.gameanalytics.com/integrations/sdk/unity/" } #else new StringWithType { Text = "Your selected build platform is not currently supported by GameAnalytics." }, - new StringWithType { Text = "The Unity SDK includes support for Windows, Mac, Linux, WebGL, iOS, tvOS, UWP, Tizen, Universal Windows 8 and Android.", Type = StringType.Link, Link = "https://github.com/GameAnalytics/GA-SDK-UNITY" }, + new StringWithType { Text = "The Unity SDK includes support for Windows, Mac, Linux, WebGL, iOS, tvOS, UWP, Tizen, Universal Windows 8 and Android.", Type = StringType.Link, Link = "https://docs.gameanalytics.com/integrations/sdk/unity" }, #endif }; @@ -1264,29 +416,30 @@ private StringWithType[] GetGuideStepText(int step) } } - private string GetGuideStepNext(int step) + private string GetGuideStepNext(TourSteps step) { - switch (step) + TourSteps next = step + 1; + switch (next) { - case 1: + case TourSteps.AddObject: return "In the next step we look at how to add the GameAnalytics object."; - case 2: + case TourSteps.StartTracking: return "In the next step we look at how to start tracking events."; - case 3: + case TourSteps.TrackBusiness: return "In the next step we look at how to track real money transactions."; - case 4: + case TourSteps.TrackResources: return "In the next step we look at how to balance your virtual economy."; - case 5: + case TourSteps.TrackProgression: return "In the next step we look at how to track player progression."; - case 6: + case TourSteps.TrackDesign: return "In the next step we look at how to use custom design events."; - case 7: + case TourSteps.LogErrors: return "In the next step we look at how to log error events."; - case 8: + case TourSteps.CustomDimensions: return "In the next step we look at how to use custom dimensions."; - case 9: + case TourSteps.FinishGuide: return "In the last step we look at completing the integration."; - case 10: + case TourSteps.AllSteps: return "Thank you for choosing GameAnalytics!"; default: return "-"; @@ -1363,23 +516,12 @@ private void PaintAppStoreIcon(string storeName) } } -#if UNITY_2017_1_OR_NEWER public IEnumerator GetAppStoreIconTexture(UnityWebRequest www, string storeName, GA_SignUp signup) -#else - public IEnumerator GetAppStoreIconTexture(WWW www, string storeName, GA_SignUp signup) -#endif { -#if UNITY_2017_1_OR_NEWER -#if UNITY_2017_2_OR_NEWER yield return www.SendWebRequest(); -#else - yield return www.Send(); -#endif + while (!www.isDone) yield return null; -#else - yield return www; -#endif try { @@ -1437,82 +579,4 @@ public IEnumerator GetAppStoreIconTexture(WWW www, string storeName, GA_Sig } } } - - public class AppFiguresGame - { - public string Name { get; private set; } - - public string AppID { get; private set; } - - public string Store { get; private set; } - - public string Developer { get; private set; } - - public string IconUrl { get; private set; } - - public Texture2D Icon { get; private set; } - - public AppFiguresGame(string name, string appID, string store, string developer, string iconUrl, GA_SignUp signup) - { - Name = name; - AppID = appID; - Store = store; - Developer = developer; - IconUrl = iconUrl; - -#if UNITY_2017_1_OR_NEWER - UnityWebRequest www = UnityWebRequestTexture.GetTexture(iconUrl); - GA_ContinuationManager.StartCoroutine(GetIconTexture(www, signup), () => www.isDone); -#else - WWW www = new WWW(iconUrl); - GA_ContinuationManager.StartCoroutine(GetIconTexture(www, signup), () => www.isDone); -#endif - } - -#if UNITY_2017_1_OR_NEWER - private IEnumerator GetIconTexture(UnityWebRequest www, GA_SignUp signup) -#else - private IEnumerator GetIconTexture(WWW www, GA_SignUp signup) -#endif - { -#if UNITY_2017_1_OR_NEWER -#if UNITY_2017_2_OR_NEWER - yield return www.SendWebRequest(); -#else - yield return www.Send(); -#endif - while (!www.isDone) - yield return null; -#else - yield return www; -#endif - - try - { -#if UNITY_2020_1_OR_NEWER - if (!(www.result == UnityWebRequest.Result.ConnectionError || www.result == UnityWebRequest.Result.ProtocolError)) -#elif UNITY_2017_1_OR_NEWER - if (!(www.isNetworkError || www.isHttpError)) -#else - if (string.IsNullOrEmpty(www.error)) -#endif - { -#if UNITY_2017_1_OR_NEWER - Icon = ((DownloadHandlerTexture)www.downloadHandler).texture; -#else - Icon = www.texture; -#endif - signup.Repaint(); - } - else - { - Debug.LogError("Failed to get icon: " + www.error); - } - } - catch - { - Debug.LogError("Failed to get icon"); - } - } - } } diff --git a/Runtime/Scripts/Events/GA_SpecialEvents.cs b/Runtime/Scripts/Events/GA_SpecialEvents.cs index 9ba16e8..bbb5c7a 100644 --- a/Runtime/Scripts/Events/GA_SpecialEvents.cs +++ b/Runtime/Scripts/Events/GA_SpecialEvents.cs @@ -133,7 +133,7 @@ public static void SubmitFPS() { if(GameAnalytics.Initialized) GameAnalytics.NewDesignEvent("GA:CriticalFPS", _criticalFpsCount); - + _criticalFpsCount = 0; } } diff --git a/Runtime/Scripts/Setup/Settings.cs b/Runtime/Scripts/Setup/Settings.cs index fee1eb8..f42c056 100644 --- a/Runtime/Scripts/Setup/Settings.cs +++ b/Runtime/Scripts/Setup/Settings.cs @@ -53,7 +53,7 @@ public struct HelpInfo /// The version of the GA Unity Wrapper plugin /// [HideInInspector] - public static string VERSION = "7.10.2"; + public static string VERSION = "7.10.3"; [HideInInspector] public static bool CheckingForUpdates = false; diff --git a/Runtime/iOS/libGameAnalytics.a b/Runtime/iOS/libGameAnalytics.a index ef0d6bdfc50b336229006cf03f469c1b1916ba59..f67f1264b382ae58280f1234a685a63ffa20e85a 100644 GIT binary patch delta 30751 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�tGIGd7Mh=ztR z4w=ZvArl!nWFjMnOl0JciHsaFk�tjyB=PBK`s7kco^OGLex(CNgr!L`Dvo$jBiR z898JkBZo|6FWFj*-WFn&~kwYdj%^?#R zf9({=Arq&!i;#(o95RuSLnbnE$V5gCnaIc?6B#*VV&?}D3WrQ&{B#l8KmXv6iHsaF zk�tGIGd7Mh=ztR4w=ZvArl!nWTHJ%giK`Qkco_I zC346_ra5FHW78v&!66fw!66gvZ%6AP6B#*VBI6#395Rt<4w=ZvArl!nWFjMnOl0Jc ziHsaFk�tGIGeo{%hvxArpa33WrSeUKFc`Ol0JciHsaFk�tGIGeo$&X_7kcoA^ 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 Jrd4+Y{a^4G?tuUR delta 31478 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 diff --git a/package.json b/package.json index 2f1a359..796a48e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.gameanalytics.sdk", - "version": "7.10.2", + "version": "7.10.3", "displayName": "GameAnalytics", "description": "GameAnalytics collects and stores your data with no limits. You can then view your core KPI's in order to see what areas of your game need to improvements. If you want to find out more about how gamers play, then add in funnels, progression events and resource tracking. ", "unity": "2018.1",