// Generate a static class containing constants of IAP product names. void GenerateIAPConstants() { // First create a hashtable containing all the names to be stored as constants. SerializedProperty productsProp = IAPProperties.products.property; // First check if there're duplicate names. string duplicateLdbName = EM_EditorUtil.FindDuplicateNameInArrayProperty(productsProp, IAPProduct_NameProperty); if (!string.IsNullOrEmpty(duplicateLdbName)) { EM_EditorUtil.Alert("Error: Duplicate Names", "Found duplicate product name of \"" + duplicateLdbName + "\"."); return; } // Proceed with adding resource keys. Hashtable resourceKeys = new Hashtable(); // Add the product names. for (int i = 0; i < productsProp.arraySize; i++) { SerializedProperty element = productsProp.GetArrayElementAtIndex(i); string name = element.FindPropertyRelative(IAPProduct_NameProperty).stringValue; // Ignore all items with an empty name. if (!string.IsNullOrEmpty(name)) { string key = "Product_" + name; resourceKeys.Add(key, name); } } if (resourceKeys.Count > 0) { // Now build the class. EM_EditorUtil.GenerateConstantsClass( EM_Constants.GeneratedFolder, EM_Constants.RootNameSpace + "." + EM_Constants.IAPConstantsClassName, resourceKeys, true ); } else { EM_EditorUtil.Alert("Constants Class Generation", "Please fill in required information for all products."); } }
void IAPModuleGUI() { EditorGUILayout.BeginVertical(EM_GUIStyleManager.GetCustomStyle("Module Box")); EditorGUI.BeginChangeCheck(); isIAPModuleEnable.boolValue = EM_EditorGUI.ModuleToggle(isIAPModuleEnable.boolValue, IAPModuleLabel); if (EditorGUI.EndChangeCheck()) { GameObject prefab = EM_EditorUtil.GetMainPrefab(); if (!isIAPModuleEnable.boolValue) { EM_Manager.DisableIAPModule(prefab); } else { EM_Manager.EnableIAPModule(prefab); } } // Now draw the GUI. if (!isIAPModuleEnable.boolValue) { EditorGUILayout.Space(); EditorGUILayout.HelpBox(IAPModuleIntro, MessageType.Info); } else { #if !EM_UIAP EditorGUILayout.Space(); EditorGUILayout.HelpBox(UnityIAPEnableInstruction, MessageType.Error); #else // Select target Android store, like using the Window > Unity IAP > Android > Target ... menu item. EditorGUILayout.Space(); EditorGUILayout.LabelField("[ANDROID] TARGET STORE", EditorStyles.boldLabel); EditorGUI.BeginChangeCheck(); IAPProperties.targetAndroidStore.property.enumValueIndex = EditorGUILayout.Popup( IAPProperties.targetAndroidStore.content.text, IAPProperties.targetAndroidStore.property.enumValueIndex, IAPProperties.targetAndroidStore.property.enumDisplayNames ); if (EditorGUI.EndChangeCheck()) { SetTargetAndroidStore((IAPAndroidStore)IAPProperties.targetAndroidStore.property.enumValueIndex); } // Receipt validation EditorGUILayout.Space(); EditorGUILayout.LabelField("RECEIPT VALIDATION", EditorStyles.boldLabel); EditorGUILayout.HelpBox("Unity IAP offers local receipt validation for extra security. Apple stores and Google Play store only.", MessageType.None); // iOS store. EditorGUI.BeginDisabledGroup(!isAppleTangleValid); IAPProperties.validateAppleReceipt.property.boolValue = EditorGUILayout.Toggle(IAPProperties.validateAppleReceipt.content, IAPProperties.validateAppleReceipt.property.boolValue); EditorGUI.EndDisabledGroup(); // Always disable the option if AppleTangle is not valid. if (!isAppleTangleValid) { IAPProperties.validateAppleReceipt.property.boolValue = false; } // Google Play store. bool isTargetingGooglePlay = IAPProperties.targetAndroidStore.property.enumValueIndex == (int)IAPAndroidStore.GooglePlay; EditorGUI.BeginDisabledGroup(!isGooglePlayTangleValid); IAPProperties.validateGooglePlayReceipt.property.boolValue = EditorGUILayout.Toggle(IAPProperties.validateGooglePlayReceipt.content, IAPProperties.validateGooglePlayReceipt.property.boolValue); EditorGUI.EndDisabledGroup(); // Always disable the option if GooglePlayTangle is not valid. if (!isGooglePlayTangleValid) { IAPProperties.validateGooglePlayReceipt.property.boolValue = false; } if (!isAppleTangleValid || (!isGooglePlayTangleValid && isTargetingGooglePlay)) { string rvMsg = "Please go to Window > Unity IAP > IAP Receipt Validation Obfuscator and create obfuscated secrets to enable receipt validation for Apple stores and Google Play store."; if (!isAppleTangleValid) { rvMsg += " Note that you don't need to provide a Google Play public key if you're only targeting Apple stores."; } else { rvMsg = rvMsg.Replace("Apple stores and ", ""); } if (isGooglePlayTangleValid || !isTargetingGooglePlay) { rvMsg = rvMsg.Replace(" and Google Play store", ""); } EditorGUILayout.HelpBox(rvMsg, MessageType.Warning); } // Product list EditorGUILayout.Space(); EditorGUILayout.LabelField("PRODUCTS", EditorStyles.boldLabel); EMProperty products = IAPProperties.products; if (products.property.arraySize > 0) { EditorGUI.indentLevel++; isIAPProductsFoldout = EditorGUILayout.Foldout(isIAPProductsFoldout, products.property.arraySize + " " + products.content.text); EditorGUI.indentLevel--; if (isIAPProductsFoldout) { // Index of the element on which buttons are clicked. int deleteIndex = -1; int moveUpIndex = -1; int moveDownIndex = -1; for (int i = 0; i < products.property.arraySize; i++) { SerializedProperty element = products.property.GetArrayElementAtIndex(i); bool isDeleted = false; bool isMovedUp = false; bool isMovedDown = false; EditorGUILayout.Space(); DrawIAPProduct( element, ref isDeleted, ref isMovedUp, ref isMovedDown, i > 0, i < products.property.arraySize - 1 ); if (isDeleted) { deleteIndex = i; } if (isMovedUp) { moveUpIndex = i; } if (isMovedDown) { moveDownIndex = i; } } // Delete. if (deleteIndex >= 0) { products.property.DeleteArrayElementAtIndex(deleteIndex); } // Move up. if (moveUpIndex > 0) { products.property.MoveArrayElement(moveUpIndex, moveUpIndex - 1); } // Move down. if (moveDownIndex >= 0 && moveDownIndex < products.property.arraySize - 1) { products.property.MoveArrayElement(moveDownIndex, moveDownIndex + 1); } // Detect duplicate product names. string duplicateName = EM_EditorUtil.FindDuplicateNameInArrayProperty(products.property, IAPProduct_NameProperty); if (!string.IsNullOrEmpty(duplicateName)) { EditorGUILayout.Space(); EditorGUILayout.HelpBox("Found duplicate name of \"" + duplicateName + "\".", MessageType.Warning); } } } else { EditorGUILayout.HelpBox("No products added.", MessageType.None); } EditorGUILayout.Space(); if (GUILayout.Button("Add New Product", GUILayout.Height(EM_GUIStyleManager.buttonHeight))) { // Add new IAP product. AddNewProduct(products.property); // Open the foldout if it's closed. isIAPProductsFoldout = true; } // Constant generation. EditorGUILayout.Space(); EditorGUILayout.LabelField("CONSTANTS CLASS GENERATION", EditorStyles.boldLabel); EditorGUILayout.HelpBox(IAPConstantGenerationIntro, MessageType.None); EditorGUILayout.Space(); if (GUILayout.Button("Generate Constants Class", GUILayout.Height(EM_GUIStyleManager.buttonHeight))) { GenerateIAPConstants(); } #endif } EditorGUILayout.EndVertical(); }
// Draw the array of leaderboards or achievements inside a foldout and the relevant buttons. void DrawGameServiceItemArray(string itemType, EMProperty myProp, ref bool isFoldout) { if (myProp.property.arraySize > 0) { EditorGUI.indentLevel++; isFoldout = EditorGUILayout.Foldout(isFoldout, myProp.property.arraySize + " " + myProp.content.text); EditorGUI.indentLevel--; if (isFoldout) { //Prepare a string array of Android GPGPS ids to display in the leaderboards and achievements. string[] gpgsIds = new string[gpgsIdDict.Count + 1]; gpgsIds[0] = EM_Constants.NoneSymbol; gpgsIdDict.Keys.CopyTo(gpgsIds, 1); // Index of the element on which buttons are clicked. int deleteIndex = -1; int moveUpIndex = -1; int moveDownIndex = -1; for (int i = 0; i < myProp.property.arraySize; i++) { SerializedProperty element = myProp.property.GetArrayElementAtIndex(i); bool isDeleted = false; bool isMovedUp = false; bool isMovedDown = false; EditorGUILayout.Space(); DrawGameServiceItem( itemType, element, gpgsIds, ref isDeleted, ref isMovedUp, ref isMovedDown, i > 0, i < myProp.property.arraySize - 1 ); if (isDeleted) { deleteIndex = i; } if (isMovedUp) { moveUpIndex = i; } if (isMovedDown) { moveDownIndex = i; } } // Delete. if (deleteIndex >= 0) { myProp.property.DeleteArrayElementAtIndex(deleteIndex); } // Move up. if (moveUpIndex > 0) { myProp.property.MoveArrayElement(moveUpIndex, moveUpIndex - 1); } // Move down. if (moveDownIndex >= 0 && moveDownIndex < myProp.property.arraySize - 1) { myProp.property.MoveArrayElement(moveDownIndex, moveDownIndex + 1); } // Detect duplicate names. string duplicateName = EM_EditorUtil.FindDuplicateNameInArrayProperty(myProp.property, GameServiceItem_NameProperty); if (!string.IsNullOrEmpty(duplicateName)) { EditorGUILayout.Space(); EditorGUILayout.HelpBox("Found duplicate name of \"" + duplicateName + "\".", MessageType.Warning); } } } else { EditorGUILayout.HelpBox("No " + itemType + " added.", MessageType.None); } EditorGUILayout.Space(); if (GUILayout.Button("Add New " + itemType, GUILayout.Height(EM_GUIStyleManager.buttonHeight))) { // Add new leaderboard. AddNewGameServiceItem(myProp.property); // Open the foldout if it's closed. isFoldout = true; } }
// Generate a static class containing constants of leaderboard and achievement names. void GenerateGameServiceConstants() { // First create a hashtable containing all the names to be stored as constants. SerializedProperty ldbProp = GameServiceProperties.leaderboards.property; SerializedProperty acmProp = GameServiceProperties.achievements.property; // First check if there're duplicate names. string duplicateLdbName = EM_EditorUtil.FindDuplicateNameInArrayProperty(ldbProp, GameServiceItem_NameProperty); if (!string.IsNullOrEmpty(duplicateLdbName)) { EM_EditorUtil.Alert("Error: Duplicate Names", "Found duplicate leaderboard name of \"" + duplicateLdbName + "\"."); return; } string duplicateAcmName = EM_EditorUtil.FindDuplicateNameInArrayProperty(acmProp, GameServiceItem_NameProperty); if (!string.IsNullOrEmpty(duplicateAcmName)) { EM_EditorUtil.Alert("Error: Duplicate Names", "Found duplicate achievement name of \"" + duplicateAcmName + "\"."); return; } // Proceed with adding resource keys. Hashtable resourceKeys = new Hashtable(); // Add the leaderboard names. for (int i = 0; i < ldbProp.arraySize; i++) { SerializedProperty element = ldbProp.GetArrayElementAtIndex(i); string name = element.FindPropertyRelative(GameServiceItem_NameProperty).stringValue; // Ignore all items with an empty name. if (!string.IsNullOrEmpty(name)) { string key = "Leaderboard_" + name; resourceKeys.Add(key, name); } } // Add the achievement names. for (int j = 0; j < acmProp.arraySize; j++) { SerializedProperty element = acmProp.GetArrayElementAtIndex(j); string name = element.FindPropertyRelative(GameServiceItem_NameProperty).stringValue; // Ignore all items with an empty name. if (!string.IsNullOrEmpty(name)) { string key = "Achievement_" + name; resourceKeys.Add(key, name); } } if (resourceKeys.Count > 0) { // Now build the class. EM_EditorUtil.GenerateConstantsClass( EM_Constants.GeneratedFolder, EM_Constants.RootNameSpace + "." + EM_Constants.GameServiceConstantsClassName, resourceKeys, true ); } else { EM_EditorUtil.Alert("Constants Class Generation", "Please fill in required information for all leaderboards and achievements."); } }