#if UNITY_EDITOR using System; using UnityEditor; using UnityEditorInternal; using UnityEngine; using ConjureOS.CustomWindow; namespace ConjureOS.MetadataWindow { public class ConjureArcadeMetadataWindow : EditorWindow { private const string WindowName = "Arcade Game Metadata Editor"; // Game Metadata private static ConjureArcadeMetadata metadata; private ConjureArcadeMetadataValidator metadataValidator; private SerializedObject serializedObject; // Metadata Properties private SerializedProperty gameTitleProperty; private SerializedProperty versionProperty; private SerializedProperty descriptionProperty; private SerializedProperty minNumPlayerProperty; private SerializedProperty maxNumPlayerProperty; private SerializedProperty useLeaderboardProperty; private SerializedProperty thumbnailProperty; private SerializedProperty gameplayImageProperty; private SerializedProperty developersProperty; private SerializedProperty genresProperty; private ReorderableList developersList; private ReorderableList genresList; // UI Properties private Vector2 scrollPos = Vector2.zero; private void OnEnable() { metadataValidator = new ConjureArcadeMetadataValidator(); titleContent = new GUIContent(WindowName); if (!metadata) { OnLoad(); } serializedObject = new SerializedObject(metadata); SetUpProperties(serializedObject); } [InitializeOnLoadMethod] private static void OnLoad() { if (!metadata) { metadata = AssetDatabase.LoadAssetAtPath(ConjureArcadeMetadata.MetadataAssetPath); // Data exists if (metadata) { return; } metadata = CreateInstance(); AssetDatabase.CreateAsset(metadata, ConjureArcadeMetadata.MetadataAssetPath); AssetDatabase.Refresh(); } } private void OnGUI() { serializedObject.Update(); // Add padding to the window int globalSpace = 2; int uniformPadding = ConjureArcadeGUI.Style.UniformPadding; RectOffset padding = new RectOffset(uniformPadding, uniformPadding, 0, 0); Rect area = new Rect( padding.right, padding.top, position.width - (padding.left), position.height - (padding.top + padding.bottom)); // Generate input fields GUILayout.BeginArea(area); // Scrollbar RectOffset vertScrollbarPadding = new RectOffset(uniformPadding, 0, 0, 0); GUIStyle vertScrollbarSkin = new GUIStyle(GUI.skin.verticalScrollbar); vertScrollbarSkin.margin = vertScrollbarPadding; scrollPos = GUILayout.BeginScrollView(scrollPos, false, true, new GUIStyle(GUI.skin.horizontalScrollbar), vertScrollbarSkin); GUILayout.Space(uniformPadding); GUILayout.Label("GAME METADATA", EditorStyles.boldLabel); EditorGUILayout.PropertyField(gameTitleProperty, new GUIContent("Game Title")); ShowErrorMessage(metadataValidator.GameTitleErrorMessage); GUILayout.Space(globalSpace); EditorGUILayout.PropertyField(versionProperty, new GUIContent("Version")); ShowErrorMessage(metadataValidator.VersionErrorMessage); GUILayout.Space(globalSpace); EditorGUILayout.PropertyField(descriptionProperty, new GUIContent("Description"), GUILayout.Height(150)); ShowErrorMessage(metadataValidator.DescriptionErrorMessage); GUILayout.Space(globalSpace); EditorGUILayout.PropertyField(minNumPlayerProperty, new GUIContent("Min Number of Players")); ShowErrorMessage(metadataValidator.MinNumPlayerErrorMessage); GUILayout.Space(globalSpace); EditorGUILayout.PropertyField(maxNumPlayerProperty, new GUIContent("Max Number of Players")); ShowErrorMessage(metadataValidator.MaxNumPlayerErrorMessage); GUILayout.Space(globalSpace); EditorGUILayout.PropertyField(useLeaderboardProperty, new GUIContent("Use Leaderboard")); GUILayout.Space(globalSpace); EditorGUILayout.PropertyField(thumbnailProperty, new GUIContent("Thumbnail")); ShowErrorMessage(metadataValidator.ThumbnailErrorMessage); GUILayout.Space(globalSpace); EditorGUILayout.PropertyField(gameplayImageProperty, new GUIContent("Gameplay Image")); ShowErrorMessage(metadataValidator.GameplayImageErrorMessage); GUILayout.Space(globalSpace); GUILayout.Space(10); developersList.DoLayoutList(); ShowErrorMessage(metadataValidator.DevelopersErrorMessage); GUILayout.Space(10); UpdateReorderableListInteractions(genresList, ConjureArcadeMetadata.MaxSelectedGenres); genresList.DoLayoutList(); ShowErrorMessage(metadataValidator.GenresErrorMessage); GUILayout.Space(10); // Show release date and last change date ONLY if a date has been set if (metadata.ReleaseDate != DateTime.MinValue) { GUILayout.Label("Release Date: " + metadata.ReleaseDate.ToString()); } if (metadata.LastGameUpdate != DateTime.MinValue) { GUILayout.Label("Last Change: " + metadata.LastGameUpdate.ToString()); } // Validate properties and save data serializedObject.ApplyModifiedProperties(); GUILayout.Space(30); if (GUILayout.Button("Execute Validation", GUILayout.Width(150))) { metadataValidator.ValidateMetadata(metadata); } GUILayout.Space(globalSpace); ShowValidationResultMessage(); GUILayout.Space(uniformPadding); GUILayout.EndScrollView(); GUILayout.EndArea(); } private void ShowErrorMessage(string errorMessage) { if (errorMessage != string.Empty) { GUILayout.Label(errorMessage, ConjureArcadeGUI.Style.ErrorStyle); GUILayout.Space(3); } } private void ShowValidationResultMessage() { MetadataValidationStateType validationState = metadataValidator.GetValidationStateType(); switch (validationState) { case MetadataValidationStateType.NotVerified: // No message is displayed return; case MetadataValidationStateType.Validated: // No error, means it's a success GUILayout.Label(ConjureArcadeGUI.Message.MetadataConfirmedMessage, ConjureArcadeGUI.Style.SuccessStyle); GUILayout.Space(3); break; case MetadataValidationStateType.Failed: // Errors were detected string plural = (metadataValidator.ErrorCount > 1) ? "s" : ""; string formatedMessage = string.Format(ConjureArcadeGUI.Message.MetadataFailedMessage, metadataValidator.ErrorCount, plural); ShowErrorMessage(formatedMessage); break; } } private void SetUpProperties(SerializedObject serializedObject) { // Get data gameTitleProperty = serializedObject.FindProperty("gameTitle"); versionProperty = serializedObject.FindProperty("version"); descriptionProperty = serializedObject.FindProperty("description"); minNumPlayerProperty = serializedObject.FindProperty("minNumPlayer"); maxNumPlayerProperty = serializedObject.FindProperty("maxNumPlayer"); useLeaderboardProperty = serializedObject.FindProperty("useLeaderboard"); thumbnailProperty = serializedObject.FindProperty("thumbnail"); gameplayImageProperty = serializedObject.FindProperty("gameplayImage"); // Get developers data and prepare list developersProperty = serializedObject.FindProperty("developers"); developersList = new ReorderableList(serializedObject, developersProperty, true, true, true, true); developersList.drawElementCallback = DrawDevelopersListItems; developersList.drawHeaderCallback = DrawDevelopersListHeader; developersList.onReorderCallback = OnDevelopersReorder; // Get genres data and prepare list genresProperty = serializedObject.FindProperty("genres"); genresList = new ReorderableList(serializedObject, genresProperty, true, true, true, true); genresList.drawElementCallback = DrawGenresListItems; genresList.drawHeaderCallback = DrawGenresListHeader; } private void UpdateReorderableListInteractions(ReorderableList list, int countLimit) { // Hide or show the "Add" button only if the count limit has not been reached if (genresList.count >= countLimit) { list.displayAdd = false; } else { list.displayAdd = true; } } // ReorderableList Callbacks ===== private void DrawGenresListItems(Rect rect, int index, bool isActive, bool isFocused) { // Get the selected genre of the current item var element = genresProperty.GetArrayElementAtIndex(index); var selectedGenre = element.FindPropertyRelative(nameof(GameGenre.selectedGenre)); var popupHeight = EditorGUI.GetPropertyHeight(selectedGenre); // Create popup selectedGenre.intValue = EditorGUI.Popup(new Rect(rect.x, rect.y, rect.width, popupHeight), selectedGenre.intValue, ConjureArcadeMetadata.GenreOptions); } private void DrawDevelopersListItems(Rect rect, int index, bool isActive, bool isFocused) { // Get the selected genre of the current item var element = developersProperty.GetArrayElementAtIndex(index); // Create popup GUIStyle fieldErrorIndicatorStyle = new GUIStyle(EditorStyles.textField); fieldErrorIndicatorStyle.normal.textColor = ConjureArcadeGUI.Style.ColorError; for (int i = 0; i < metadataValidator.DevelopersErrorIndex.Count; i++) { if (index == metadataValidator.DevelopersErrorIndex[i]) { element.stringValue = EditorGUI.TextField(new Rect(rect.x, rect.y, rect.width, rect.height), element.stringValue, fieldErrorIndicatorStyle); return; } } element.stringValue = EditorGUI.TextField(new Rect(rect.x, rect.y, rect.width, rect.height), element.stringValue); } private void DrawGenresListHeader(Rect rect) { DrawListHeader(rect, "Genres"); } private void DrawDevelopersListHeader(Rect rect) { DrawListHeader(rect, "Developers"); } private void DrawListHeader(Rect rect, string name) { EditorGUI.LabelField(rect, name); } private void OnDevelopersReorder(ReorderableList reList) { // On reorder of the developers list, data are revalidated because of the new order serializedObject.ApplyModifiedProperties(); metadataValidator.ValidateDevelopersList(metadata.Developers); } } } #endif