// -------------------------------------------------------------------------------------------------------------------- // // Part of: Photon Unity Utilities, // // // Custom inspector for PhotonTeamsManager // // developer@exitgames.com // -------------------------------------------------------------------------------------------------------------------- using System; using UnityEngine; using System.Collections.Generic; using Photon.Realtime; using UnityEditor; namespace Photon.Pun.UtilityScripts { [CustomEditor(typeof(PhotonTeamsManager))] public class PhotonTeamsManagerEditor : Editor { private Dictionary foldouts = new Dictionary(); private PhotonTeamsManager photonTeams; private SerializedProperty teamsListSp; private SerializedProperty listFoldIsOpenSp; private const string proSkinString = "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAECAYAAACzzX7wAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi/P//PwM+wHL06FG8KpgYCABGZWVlvCYABBgA7/sHvGw+cz8AAAAASUVORK5CYII="; private const string lightSkinString = "iVBORw0KGgoAAAANSUhEUgAAAAgAAAACCAIAAADq9gq6AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABVJREFUeNpiVFZWZsAGmBhwAIAAAwAURgBt4C03ZwAAAABJRU5ErkJggg=="; private const string removeTextureName = "removeButton_generated"; private Texture removeTexture; private bool isOpen; public override bool RequiresConstantRepaint() { return true; } private void OnEnable() { photonTeams = target as PhotonTeamsManager; teamsListSp = serializedObject.FindProperty("teamsList"); listFoldIsOpenSp = serializedObject.FindProperty("listFoldIsOpen"); isOpen = listFoldIsOpenSp.boolValue; removeTexture = LoadTexture(removeTextureName, proSkinString, lightSkinString); } /// /// Read width and height if PNG file in pixels. /// /// PNG image data. /// Width of image in pixels. /// Height of image in pixels. private static void GetImageSize( byte[] imageData, out int width, out int height ) { width = ReadInt( imageData, 3 + 15 ); height = ReadInt( imageData, 3 + 15 + 2 + 2 ); } private static int ReadInt( byte[] imageData, int offset ) { return ( imageData[ offset ] << 8 ) | imageData[ offset + 1 ]; } private Texture LoadTexture(string textureName, string proSkin, string lightSkin) { string skin = EditorGUIUtility.isProSkin ? proSkin : lightSkin; // Get image data (PNG) from base64 encoded strings. byte[] imageData = Convert.FromBase64String( skin ); // Gather image size from image data. int texWidth, texHeight; GetImageSize( imageData, out texWidth, out texHeight ); // Generate texture asset. var tex = new Texture2D( texWidth, texHeight, TextureFormat.ARGB32, false, true ); tex.hideFlags = HideFlags.HideAndDontSave; tex.name = textureName; tex.filterMode = FilterMode.Point; tex.LoadImage( imageData ); return tex; } public override void OnInspectorGUI() { if (!Application.isPlaying) { DrawTeamsList(); return; } PhotonTeam[] availableTeams = photonTeams.GetAvailableTeams(); if (availableTeams != null) { EditorGUI.indentLevel++; foreach (var availableTeam in availableTeams) { if (!foldouts.ContainsKey(availableTeam.Code)) { foldouts[availableTeam.Code] = true; } Player[] teamMembers; if (photonTeams.TryGetTeamMembers(availableTeam, out teamMembers) && teamMembers != null) { foldouts[availableTeam.Code] = EditorGUILayout.Foldout(foldouts[availableTeam.Code], string.Format("{0} ({1})", availableTeam.Name, teamMembers.Length)); } else { foldouts[availableTeam.Code] = EditorGUILayout.Foldout(foldouts[availableTeam.Code], string.Format("{0} (0)", availableTeam.Name)); } if (foldouts[availableTeam.Code] && teamMembers != null) { EditorGUI.indentLevel++; foreach (var player in teamMembers) { EditorGUILayout.LabelField(string.Empty, string.Format("{0} {1}", player, player.IsLocal ? " - You -" : string.Empty)); } EditorGUI.indentLevel--; } } EditorGUI.indentLevel--; } } private void DrawTeamsList() { GUILayout.Space(5); HashSet codes = new HashSet(); HashSet names = new HashSet(); for (int i = 0; i < teamsListSp.arraySize; i++) { SerializedProperty e = teamsListSp.GetArrayElementAtIndex(i); string name = e.FindPropertyRelative("Name").stringValue; byte code = (byte)e.FindPropertyRelative("Code").intValue; codes.Add(code); names.Add(name); } this.serializedObject.Update(); EditorGUI.BeginChangeCheck(); isOpen = PhotonGUI.ContainerHeaderFoldout(string.Format("Teams List ({0})", teamsListSp.arraySize), isOpen); if (EditorGUI.EndChangeCheck()) { listFoldIsOpenSp.boolValue = isOpen; } if (isOpen) { const float containerElementHeight = 22; const float propertyHeight = 16; const float paddingRight = 29; const float paddingLeft = 5; const float spacingY = 3; float containerHeight = (teamsListSp.arraySize + 1) * containerElementHeight; Rect containerRect = PhotonGUI.ContainerBody(containerHeight); float propertyWidth = containerRect.width - paddingRight; float codePropertyWidth = propertyWidth / 5; float namePropertyWidth = 4 * propertyWidth / 5; Rect elementRect = new Rect(containerRect.xMin, containerRect.yMin, containerRect.width, containerElementHeight); Rect propertyPosition = new Rect(elementRect.xMin + paddingLeft, elementRect.yMin + spacingY, codePropertyWidth, propertyHeight); EditorGUI.LabelField(propertyPosition, "Code"); Rect secondPropertyPosition = new Rect(elementRect.xMin + paddingLeft + codePropertyWidth, elementRect.yMin + spacingY, namePropertyWidth, propertyHeight); EditorGUI.LabelField(secondPropertyPosition, "Name"); for (int i = 0; i < teamsListSp.arraySize; ++i) { elementRect = new Rect(containerRect.xMin, containerRect.yMin + containerElementHeight * (i + 1), containerRect.width, containerElementHeight); propertyPosition = new Rect(elementRect.xMin + paddingLeft, elementRect.yMin + spacingY, codePropertyWidth, propertyHeight); SerializedProperty teamElementSp = teamsListSp.GetArrayElementAtIndex(i); SerializedProperty teamNameSp = teamElementSp.FindPropertyRelative("Name"); SerializedProperty teamCodeSp = teamElementSp.FindPropertyRelative("Code"); string oldName = teamNameSp.stringValue; byte oldCode = (byte)teamCodeSp.intValue; EditorGUI.BeginChangeCheck(); EditorGUI.PropertyField(propertyPosition, teamCodeSp, GUIContent.none); if (EditorGUI.EndChangeCheck()) { byte newCode = (byte)teamCodeSp.intValue; if (codes.Contains(newCode)) { Debug.LogWarningFormat("Team with the same code {0} already exists", newCode); teamCodeSp.intValue = oldCode; } } secondPropertyPosition = new Rect(elementRect.xMin + paddingLeft + codePropertyWidth, elementRect.yMin + spacingY, namePropertyWidth, propertyHeight); EditorGUI.BeginChangeCheck(); EditorGUI.PropertyField(secondPropertyPosition, teamNameSp, GUIContent.none); if (EditorGUI.EndChangeCheck()) { string newName = teamNameSp.stringValue; if (string.IsNullOrEmpty(newName)) { Debug.LogWarning("Team name cannot be null or empty"); teamNameSp.stringValue = oldName; } else if (names.Contains(newName)) { Debug.LogWarningFormat("Team with the same name \"{0}\" already exists", newName); teamNameSp.stringValue = oldName; } } Rect removeButtonRect = new Rect( elementRect.xMax - PhotonGUI.DefaultRemoveButtonStyle.fixedWidth, elementRect.yMin + 2, PhotonGUI.DefaultRemoveButtonStyle.fixedWidth, PhotonGUI.DefaultRemoveButtonStyle.fixedHeight); if (GUI.Button(removeButtonRect, new GUIContent(removeTexture), PhotonGUI.DefaultRemoveButtonStyle)) { teamsListSp.DeleteArrayElementAtIndex(i); } if (i < teamsListSp.arraySize - 1) { Rect texturePosition = new Rect(elementRect.xMin + 2, elementRect.yMax, elementRect.width - 4, 1); PhotonGUI.DrawSplitter(texturePosition); } } } if (PhotonGUI.AddButton()) { byte c = 0; while (codes.Contains(c) && c < byte.MaxValue) { c++; } this.teamsListSp.arraySize++; SerializedProperty teamElementSp = this.teamsListSp.GetArrayElementAtIndex(teamsListSp.arraySize - 1); SerializedProperty teamNameSp = teamElementSp.FindPropertyRelative("Name"); SerializedProperty teamCodeSp = teamElementSp.FindPropertyRelative("Code"); teamCodeSp.intValue = c; string n = "New Team"; int o = 1; while (names.Contains(n)) { n = string.Format("New Team {0}", o); o++; } teamNameSp.stringValue = n; } this.serializedObject.ApplyModifiedProperties(); } } }