using System; using UnityEngine; using UnityEditor; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Text.RegularExpressions; using ABI.CCK.Components; using UnityEditor.Profiling; using UnityEditorInternal; using UnityEngine.SceneManagement; using UnityEngine.UI; using AnimatorController = UnityEditor.Animations.AnimatorController; using AnimatorControllerParameterType = UnityEngine.AnimatorControllerParameterType; namespace ABI.CCK.Scripts.Editor { [CustomEditor(typeof(ABI.CCK.Components.CVRAvatar))] public class CCK_CVRAvatarEditor : UnityEditor.Editor { private static string[] _visemeNames = new[] {"sil", "PP", "FF", "TH", "DD", "kk", "CH", "SS", "nn", "RR", "aa", "E", "ih", "oh", "ou"}; public static string[] coreParameters = {"MovementX", "MovementY", "Grounded", "Emote", "GestureLeft", "GestureRight", "Toggle", "Sitting", "Crouching", "CancelEmote", "Prone", "Flying"}; private CVRAvatar _avatar; private int _blink; private List _blendShapeNames = null; private ReorderableList reorderableList; private CVRAdvancedSettingsEntry entity = null; private int syncedValues = 0; private int syncedBooleans = 0; private List animatorParameters = new List(); private bool definitionContainsError = false; private ReorderableList taggingList; private CVRAvatarAdvancedTaggingEntry tagEntry; private void InitializeList() { if (_avatar.avatarSettings == null) return; reorderableList = new ReorderableList(_avatar.avatarSettings.settings, typeof(CVRAdvancedSettingsEntry), true, true, true, true); reorderableList.drawHeaderCallback = OnDrawHeader; reorderableList.drawElementCallback = OnDrawElement; reorderableList.elementHeightCallback = OnHeightElement; reorderableList.onAddCallback = OnAdd; reorderableList.onChangedCallback = OnChanged; } private void InitializeTaggingList() { taggingList = new ReorderableList(_avatar.advancedTaggingList, typeof(CVRAvatarAdvancedTaggingEntry), false, true, true, true); taggingList.drawHeaderCallback = OnDrawHeaderTagging; taggingList.drawElementCallback = OnDrawElementTagging; taggingList.elementHeightCallback = OnHeightElementTagging; taggingList.onAddCallback = OnAddTagging; taggingList.onChangedCallback = OnChangedTagging; } public override void OnInspectorGUI() { if (_avatar == null) _avatar = (CVRAvatar) target; GetBlendShapeNames(); EditorGUILayout.LabelField("General avatar settings", EditorStyles.boldLabel); _avatar.viewPosition = EditorGUILayout.Vector3Field("View Position", _avatar.viewPosition); EditorGUILayout.HelpBox(CCKLocalizationProvider.GetLocalizedText("ABI_UI_AVATAR_INFO_VIEWPOINT"), MessageType.Info); _avatar.voicePosition = EditorGUILayout.Vector3Field("Voice Position", _avatar.voicePosition); _avatar.voiceParent = (CVRAvatar.CVRAvatarVoiceParent) EditorGUILayout.EnumPopup("Voice Parent", _avatar.voiceParent); EditorGUILayout.HelpBox(CCKLocalizationProvider.GetLocalizedText("ABI_UI_AVATAR_INFO_VOICE_POSITION"), MessageType.Info); EditorGUILayout.LabelField(""); EditorGUILayout.LabelField("Avatar customization", EditorStyles.boldLabel); _avatar.overrides = (AnimatorOverrideController)EditorGUILayout.ObjectField("Animation Overrides", _avatar.overrides, typeof(AnimatorOverrideController), true, null); EditorGUILayout.HelpBox(CCKLocalizationProvider.GetLocalizedText("ABI_UI_AVATAR_INFO_OVERRIDE_CONTROLLER"), MessageType.Info); EditorGUILayout.LabelField(""); EditorGUILayout.LabelField("Blinking and Visemes", EditorStyles.boldLabel); _avatar.bodyMesh = (SkinnedMeshRenderer)EditorGUILayout.ObjectField("Face Mesh", _avatar.bodyMesh, typeof(SkinnedMeshRenderer), true); _avatar.useEyeMovement = EditorGUILayout.Toggle("Use Eye Movement", _avatar.useEyeMovement); EditorGUILayout.HelpBox(CCKLocalizationProvider.GetLocalizedText("ABI_UI_AVATAR_INFO_EYE_MOVEMENT"), MessageType.Info); _avatar.useBlinkBlendshapes = EditorGUILayout.Toggle("Use Blink Blendshapes", _avatar.useBlinkBlendshapes); EditorGUILayout.HelpBox(CCKLocalizationProvider.GetLocalizedText("ABI_UI_AVATAR_INFO_BLinking"), MessageType.Info); for (int i = 0; i < 4; i++) { int current = 0; for (int j = 0; j < _blendShapeNames.Count; ++j) if (_avatar.blinkBlendshape[i] == _blendShapeNames[j]) current = j; int blink = EditorGUILayout.Popup("Blink " + (i + 1), current, _blendShapeNames.ToArray()); _avatar.blinkBlendshape[i] = _blendShapeNames[blink]; } EditorGUILayout.Space(); _avatar.useVisemeLipsync = EditorGUILayout.Toggle("Use Lip Sync", _avatar.useVisemeLipsync); _avatar.visemeMode = (CVRAvatar.CVRAvatarVisemeMode) EditorGUILayout.EnumPopup("Lip Sync Mode", _avatar.visemeMode); if (_avatar.visemeBlendshapes == null || _avatar.visemeBlendshapes.Length != _visemeNames.Length) _avatar.visemeBlendshapes = new string[_visemeNames.Length]; EditorGUILayout.Space(); if (_avatar.visemeMode == CVRAvatar.CVRAvatarVisemeMode.Visemes) { for (int i = 0; i < _visemeNames.Length; i++) { int current = 0; for (int j = 0; j < _blendShapeNames.Count; ++j) if (_avatar.visemeBlendshapes[i] == _blendShapeNames[j]) current = j; int viseme = EditorGUILayout.Popup("Viseme: " + _visemeNames[i], current, _blendShapeNames.ToArray()); _avatar.visemeBlendshapes[i] = _blendShapeNames[viseme]; } if (GUILayout.Button("Auto select Visemes")) { FindVisemes(); _avatar.useVisemeLipsync = true; } EditorGUILayout.HelpBox(CCKLocalizationProvider.GetLocalizedText("ABI_UI_AVATAR_INFO_EYE_VISEMES"), MessageType.Info); } else if (_avatar.visemeMode == CVRAvatar.CVRAvatarVisemeMode.SingleBlendshape) { int current = 0; for (int j = 0; j < _blendShapeNames.Count; ++j) if (_avatar.visemeBlendshapes[0] == _blendShapeNames[j]) current = j; int viseme = EditorGUILayout.Popup("Viseme", current, _blendShapeNames.ToArray()); _avatar.visemeBlendshapes[0] = _blendShapeNames[viseme]; } //Advanced Tagging System GUILayout.BeginVertical("HelpBox"); GUILayout.BeginHorizontal(); _avatar.enableAdvancedTagging = EditorGUILayout.Toggle(_avatar.enableAdvancedTagging, GUILayout.Width(16)); EditorGUILayout.LabelField("Enable Advanced Tagging", GUILayout.Width(250)); GUILayout.EndHorizontal(); if (_avatar.enableAdvancedTagging) { EditorGUILayout.HelpBox("Attention! If you are using the Advanced Tagging System, you still need to Tag your Avatar appropriately and Set all affected GameObjects here.", MessageType.Warning); if (taggingList == null) InitializeTaggingList(); taggingList.DoLayoutList(); } GUILayout.EndVertical(); //Advanced Avatar Settings GUILayout.BeginVertical("HelpBox"); GUILayout.BeginHorizontal(); _avatar.avatarUsesAdvancedSettings = EditorGUILayout.Toggle(_avatar.avatarUsesAdvancedSettings, GUILayout.Width(16)); EditorGUILayout.LabelField("Enable Advanced Settings", GUILayout.Width(250)); GUILayout.EndHorizontal(); if (_avatar.avatarUsesAdvancedSettings) { GUILayout.BeginHorizontal(); GUILayout.BeginVertical("GroupBox"); if (_avatar.avatarSettings == null || !_avatar.avatarSettings.initialized) { CreateAvatarSettings(_avatar); } _avatar.avatarSettings.baseController = (RuntimeAnimatorController) EditorGUILayout.ObjectField("Base Animator", _avatar.avatarSettings.baseController, typeof(RuntimeAnimatorController)); if (_avatar.avatarSettings.baseController is AnimatorOverrideController) _avatar.avatarSettings.baseController = null; EditorGUILayout.HelpBox("This is the Base Animator that is extended for the creation of your Advanced Avatar Settings. "+ "If you do not want to extend a specific Animator Controller, make sure that the Default Avatar Animator "+ "From the Directory \"ABI.CCK/Animations\" is used here.", MessageType.Info); _avatar.avatarSettings.baseOverrideController = (RuntimeAnimatorController) EditorGUILayout.ObjectField("Override Controller", _avatar.avatarSettings.baseOverrideController, typeof(RuntimeAnimatorController)); if (_avatar.avatarSettings.baseOverrideController is AnimatorController) _avatar.avatarSettings.baseOverrideController = null; EditorGUILayout.HelpBox("You can Put your previous Override Controller here in order to put your overrides in "+ "the newly created Override Controller.", MessageType.Info); UpdateSyncCount(); int current = syncedValues * 32 + Mathf.CeilToInt(syncedBooleans / 8f) * 8; Rect _rect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight); EditorGUI.ProgressBar(_rect, current / 3200f, current + " of 3200 Synced Bit used"); if (reorderableList == null) InitializeList(); reorderableList.DoLayoutList(); if (!definitionContainsError) { if (GUILayout.Button("CreateAnimator")) CreateAnimator(); } if (_avatar.avatarSettings.overrides != null && _avatar.avatarSettings.overrides != _avatar.overrides) { if (GUILayout.Button("Attach created Override to Avatar")) { _avatar.overrides = _avatar.avatarSettings.overrides; } } GUILayout.EndVertical(); GUILayout.EndHorizontal(); } GUILayout.EndVertical(); if (GUI.changed) { EditorUtility.SetDirty(target); } } private void UpdateSyncCount() { syncedValues = 0; syncedBooleans = 0; if (_avatar.avatarSettings == null) return; animatorParameters.Clear(); definitionContainsError = false; if (_avatar.avatarSettings.baseController != null) { var animator = (AnimatorController) _avatar.avatarSettings.baseController; foreach (var parameter in animator.parameters) { if (parameter.type == AnimatorControllerParameterType.Float && parameter.name.Length > 0 && !coreParameters.Contains(parameter.name) && parameter.name.Substring(0, 1) != "#") { syncedValues += 1; animatorParameters.Add(parameter.name); } if (parameter.type == AnimatorControllerParameterType.Int && parameter.name.Length > 0 && !coreParameters.Contains(parameter.name) && parameter.name.Substring(0, 1) != "#") { syncedValues += 1; animatorParameters.Add(parameter.name); } if (parameter.type == AnimatorControllerParameterType.Bool && parameter.name.Length > 0 && !coreParameters.Contains(parameter.name) && parameter.name.Substring(0, 1) != "#") { syncedBooleans += 1; animatorParameters.Add(parameter.name); } } } foreach (var entry in _avatar.avatarSettings.settings) { if (entry == null) continue; if (entry.name == null) continue; if (entry.name.Length == 0) continue; if (entry.name.Substring(0, 1) == "#") continue; switch (entry.type) { case CVRAdvancedSettingsEntry.SettingsType.GameObjectToggle: if (animatorParameters.Contains(entry.machineName)) continue; if (entry.setting.usedType == CVRAdvancesAvatarSettingBase.ParameterType.GenerateBool) { syncedBooleans += 1; } else { syncedValues += 1; } break; case CVRAdvancedSettingsEntry.SettingsType.GameObjectDropdown: if (animatorParameters.Contains(entry.machineName)) continue; syncedValues += 1; break; case CVRAdvancedSettingsEntry.SettingsType.MaterialColor: if (animatorParameters.Contains(entry.machineName + "-r") || animatorParameters.Contains(entry.machineName + "-g") || animatorParameters.Contains(entry.machineName + "-b")) continue; syncedValues += 3; break; case CVRAdvancedSettingsEntry.SettingsType.Joystick2D: if (animatorParameters.Contains(entry.machineName + "-x") || animatorParameters.Contains(entry.machineName + "-y")) continue; syncedValues += 2; break; case CVRAdvancedSettingsEntry.SettingsType.Joystick3D: if (animatorParameters.Contains(entry.machineName + "-x") || animatorParameters.Contains(entry.machineName + "-y") || animatorParameters.Contains(entry.machineName + "-z")) continue; syncedValues += 3; break; case CVRAdvancedSettingsEntry.SettingsType.InputVector2: if (animatorParameters.Contains(entry.machineName + "-x") || animatorParameters.Contains(entry.machineName + "-y")) continue; syncedValues += 2; break; case CVRAdvancedSettingsEntry.SettingsType.InputVector3: if (animatorParameters.Contains(entry.machineName + "-x") || animatorParameters.Contains(entry.machineName + "-y") || animatorParameters.Contains(entry.machineName + "-z")) continue; syncedValues += 3; break; default: if (animatorParameters.Contains(entry.machineName)) continue; syncedValues += 1; break; } } } private void CreateAnimator() { if (_avatar.avatarSettings.baseController == null) { EditorUtility.DisplayDialog("Animator Error", "The Base Animator was not selected. No new Animator Controller was created.", "OK"); return; } if (_avatar.avatarSettings.animator != null) { if (!EditorUtility.DisplayDialog("Animator already created", "There is Animator already created for this avatar.", "Override", "Cancel")) { return; } } string pathToCurrentFolder = "Assets/AdvancedSettings.Generated"; if (!AssetDatabase.IsValidFolder(pathToCurrentFolder)) AssetDatabase.CreateFolder("Assets", "AdvancedSettings.Generated"); var folderPath = pathToCurrentFolder + "/" + _avatar.name + "_AAS"; if (!AssetDatabase.IsValidFolder(folderPath)) AssetDatabase.CreateFolder(pathToCurrentFolder, _avatar.name + "_AAS"); var animatorPath = pathToCurrentFolder + "/" + _avatar.name + "_AAS/" + _avatar.name + "_aas.controller"; AssetDatabase.CopyAsset(AssetDatabase.GetAssetPath(_avatar.avatarSettings.baseController.GetInstanceID()), animatorPath); _avatar.avatarSettings.animator = AssetDatabase.LoadAssetAtPath(animatorPath); animatorParameters.Clear(); if (_avatar.avatarSettings.baseController != null) { var animator = (AnimatorController) _avatar.avatarSettings.baseController; foreach (var parameter in animator.parameters) { if (parameter.type == AnimatorControllerParameterType.Float && parameter.name.Length > 0 && !coreParameters.Contains(parameter.name) && parameter.name.Substring(0, 1) != "#") { animatorParameters.Add(parameter.name); } if (parameter.type == AnimatorControllerParameterType.Int && parameter.name.Length > 0 && !coreParameters.Contains(parameter.name) && parameter.name.Substring(0, 1) != "#") { animatorParameters.Add(parameter.name); } if (parameter.type == AnimatorControllerParameterType.Bool && parameter.name.Length > 0 && !coreParameters.Contains(parameter.name) && parameter.name.Substring(0, 1) != "#") { animatorParameters.Add(parameter.name); } } } foreach (var entry in _avatar.avatarSettings.settings) { switch (entry.type) { default: if (animatorParameters.Contains(entry.machineName)) continue; break; case CVRAdvancedSettingsEntry.SettingsType.MaterialColor: if (animatorParameters.Contains(entry.machineName + "-r") || animatorParameters.Contains(entry.machineName + "-g") || animatorParameters.Contains(entry.machineName + "-b")) continue; break; case CVRAdvancedSettingsEntry.SettingsType.Joystick2D: case CVRAdvancedSettingsEntry.SettingsType.InputVector2: if (animatorParameters.Contains(entry.machineName + "-x") || animatorParameters.Contains(entry.machineName + "-y")) continue; break; case CVRAdvancedSettingsEntry.SettingsType.Joystick3D: case CVRAdvancedSettingsEntry.SettingsType.InputVector3: if (animatorParameters.Contains(entry.machineName + "-x") || animatorParameters.Contains(entry.machineName + "-y") || animatorParameters.Contains(entry.machineName + "-z")) continue; break; } entry.setting.SetupAnimator(ref _avatar.avatarSettings.animator, entry.machineName, folderPath); } if (_avatar.avatarSettings.baseOverrideController != null) { var overridePath = pathToCurrentFolder + "/" + _avatar.name + "_AAS/" + _avatar.name + "_aas_overrides.overrideController"; AssetDatabase.CopyAsset(AssetDatabase.GetAssetPath(_avatar.avatarSettings.baseOverrideController.GetInstanceID()), overridePath); _avatar.avatarSettings.overrides = AssetDatabase.LoadAssetAtPath(overridePath); _avatar.avatarSettings.overrides.runtimeAnimatorController = _avatar.avatarSettings.animator; } else { _avatar.avatarSettings.overrides = new AnimatorOverrideController(_avatar.avatarSettings.animator); AssetDatabase.CreateAsset(_avatar.avatarSettings.overrides, pathToCurrentFolder + "/" + _avatar.name + "_AAS/" + _avatar.name + "_aas_overrides.overrideController"); } AssetDatabase.SaveAssets(); } private float OnHeightElement(int index) { if (index > _avatar.avatarSettings.settings.Count) return EditorGUIUtility.singleLineHeight * 1f; entity = _avatar.avatarSettings.settings[index]; // When collapsed only return one line height if (!entity.setting.isCollapsed) return EditorGUIUtility.singleLineHeight * 1.25f; switch (entity.type) { case CVRAdvancedSettingsEntry.SettingsType.GameObjectToggle: { var gameObjectToggle = (CVRAdvancesAvatarSettingGameObjectToggle) entity.setting; if (gameObjectToggle == null || gameObjectToggle.gameObjectTargets == null) return EditorGUIUtility.singleLineHeight * 11.50f; float height = 10.50f; if (gameObjectToggle.useAnimationClip) { height -= 1.25f; } else { foreach (var target in gameObjectToggle.gameObjectTargets) { if (!target.isCollapsed) { height += 1.25f; } else { height += 3.75f; } } if (gameObjectToggle.gameObjectTargets.Count == 0) { height += 1f; } } return EditorGUIUtility.singleLineHeight * height; } case CVRAdvancedSettingsEntry.SettingsType.GameObjectDropdown: { var gameObjectDropdown = (CVRAdvancesAvatarSettingGameObjectDropdown) entity.setting; if (gameObjectDropdown == null || gameObjectDropdown.options == null) return EditorGUIUtility.singleLineHeight * 9.25f; float height = 8.25f; foreach (var option in gameObjectDropdown.options) { height += 1; if (option.isCollapsed) { height += 4; if (option.useAnimationClip) { height -= 1.5f; } else { if (option.gameObjectTargets.Count != 0) { foreach (var target in option.gameObjectTargets) { if (!target.isCollapsed) { height += 1; } else { height += 3; } } } } } } return EditorGUIUtility.singleLineHeight * height * 1.25f; } case CVRAdvancedSettingsEntry.SettingsType.MaterialColor: { var materialColor = (CVRAdvancedAvatarSettingMaterialColor) entity.setting; if (materialColor == null || materialColor.materialColorTargets == null) return EditorGUIUtility.singleLineHeight * 8f; float height = 8f; foreach (var option in materialColor.materialColorTargets) { if (!option.isCollapsed) { height += 1.25f; } else { height += 3.75f; } } if (materialColor.materialColorTargets.Count == 0) { height += 1f; } return EditorGUIUtility.singleLineHeight * height; } case CVRAdvancedSettingsEntry.SettingsType.Slider: { var slider = (CVRAdvancesAvatarSettingSlider) entity.setting; if (slider == null || slider.materialPropertyTargets == null) return EditorGUIUtility.singleLineHeight * 8f; float height = slider.useAnimationClip?8.75f:12.5f; if (slider.useAnimationClip) return height * EditorGUIUtility.singleLineHeight; foreach (var option in slider.materialPropertyTargets) { if (!option.isCollapsed) { height += 1.25f; } else { height += 5 * 1.25f; } } if (slider.materialPropertyTargets.Count == 0) { height += 1.25f; } return EditorGUIUtility.singleLineHeight * height; } case CVRAdvancedSettingsEntry.SettingsType.Joystick2D: case CVRAdvancedSettingsEntry.SettingsType.Joystick3D: return EditorGUIUtility.singleLineHeight * 11.25f; break; } return EditorGUIUtility.singleLineHeight * 8.75f; } private void OnDrawHeader(Rect rect) { Rect _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight); GUI.Label(_rect, "Inputs"); } private void OnDrawElement(Rect rect, int index, bool isActive, bool isFocused) { if (index > _avatar.avatarSettings.settings.Count) return; entity = _avatar.avatarSettings.settings[index]; rect.y += 2; rect.x += 12; rect.width -= 12; Rect _rect = new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight); entity.setting.isCollapsed = EditorGUI.Foldout(_rect, entity.setting.isCollapsed, "Name", true); _rect.x += 100; _rect.width = rect.width - 100; entity.name = EditorGUI.TextField(_rect, entity.name); // when collapsed skip rest of UI drawing if (!entity.setting.isCollapsed) { entity.RunCollapsedSetup(); return; } if (entity.name != null) { entity.machineName = Regex.Replace(entity.name, "[^a-zA-Z0-9#]", ""); } rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight); if (entity.name == "" || entity.machineName == "") { _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight * 2f); EditorGUI.HelpBox(_rect, "Name cannot be empty", MessageType.Error); definitionContainsError = true; return; } if (entity.name == null || entity.machineName == null) { definitionContainsError = true; } EditorGUI.LabelField(_rect, "Parameter"); _rect.x += 100; _rect.width = rect.width - 100; Rect warningRect = new Rect(rect.x + 60, rect.y, 20, EditorGUIUtility.singleLineHeight); switch (entity.type) { case CVRAdvancedSettingsEntry.SettingsType.GameObjectToggle: EditorGUI.LabelField(_rect, entity.machineName); if (animatorParameters.Contains(entity.machineName)) { EditorGUI.HelpBox(warningRect, "", MessageType.Warning); EditorGUI.LabelField(warningRect, new GUIContent("", "This Layer already exists and will not be regenerated.")); } break; case CVRAdvancedSettingsEntry.SettingsType.GameObjectDropdown: EditorGUI.LabelField(_rect, entity.machineName); if (animatorParameters.Contains(entity.machineName)) { EditorGUI.HelpBox(warningRect, "", MessageType.Warning); EditorGUI.LabelField(warningRect, new GUIContent("", "This Layer already exists and will not be regenerated.")); } break; case CVRAdvancedSettingsEntry.SettingsType.MaterialColor: EditorGUI.LabelField(_rect, $"{entity.machineName}-r, {entity.machineName}-g, {entity.machineName}-b"); if (animatorParameters.Contains(entity.machineName + "-r") || animatorParameters.Contains(entity.machineName + "-g") || animatorParameters.Contains(entity.machineName + "-b")) { EditorGUI.HelpBox(warningRect, "", MessageType.Warning); EditorGUI.LabelField(warningRect, new GUIContent("", "This Layer already exists and will not be regenerated.")); } break; case CVRAdvancedSettingsEntry.SettingsType.Slider: EditorGUI.LabelField(_rect, entity.machineName); if (animatorParameters.Contains(entity.machineName)) { EditorGUI.HelpBox(warningRect, "", MessageType.Warning); EditorGUI.LabelField(warningRect, new GUIContent("", "This Layer already exists and will not be regenerated.")); } break; case CVRAdvancedSettingsEntry.SettingsType.Joystick2D: EditorGUI.LabelField(_rect, $"{entity.machineName}-x, {entity.machineName}-y"); if (animatorParameters.Contains(entity.machineName + "-x") || animatorParameters.Contains(entity.machineName + "-y")) { EditorGUI.HelpBox(warningRect, "", MessageType.Warning); EditorGUI.LabelField(warningRect, new GUIContent("", "This Layer already exists and will not be regenerated.")); } break; case CVRAdvancedSettingsEntry.SettingsType.Joystick3D: EditorGUI.LabelField(_rect, $"{entity.machineName}-x, {entity.machineName}-y, {entity.machineName}-z"); if (animatorParameters.Contains(entity.machineName + "-x") || animatorParameters.Contains(entity.machineName + "-y") || animatorParameters.Contains(entity.machineName + "-z")) { EditorGUI.HelpBox(warningRect, "", MessageType.Warning); EditorGUI.LabelField(warningRect, new GUIContent("", "This Layer already exists and will not be regenerated.")); } break; case CVRAdvancedSettingsEntry.SettingsType.InputSingle: EditorGUI.LabelField(_rect, entity.machineName); if (animatorParameters.Contains(entity.machineName)) { EditorGUI.HelpBox(warningRect, "", MessageType.Warning); EditorGUI.LabelField(warningRect, new GUIContent("", "This Layer already exists and will not be regenerated.")); } break; case CVRAdvancedSettingsEntry.SettingsType.InputVector2: EditorGUI.LabelField(_rect, $"{entity.machineName}-x, {entity.machineName}-y"); if (animatorParameters.Contains(entity.machineName + "-x") || animatorParameters.Contains(entity.machineName + "-y")) { EditorGUI.HelpBox(warningRect, "", MessageType.Warning); EditorGUI.LabelField(warningRect, new GUIContent("", "This Layer already exists and will not be regenerated.")); } break; case CVRAdvancedSettingsEntry.SettingsType.InputVector3: EditorGUI.LabelField(_rect, $"{entity.machineName}-x, {entity.machineName}-y, {entity.machineName}-z"); if (animatorParameters.Contains(entity.machineName + "-x") || animatorParameters.Contains(entity.machineName + "-y") || animatorParameters.Contains(entity.machineName + "-z")) { EditorGUI.HelpBox(warningRect, "", MessageType.Warning); EditorGUI.LabelField(warningRect, new GUIContent("", "This Layer already exists and will not be regenerated.")); } break; } rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight); EditorGUI.LabelField(_rect, "Type"); _rect.x += 100; _rect.width = rect.width - 100; var type = (CVRAdvancedSettingsEntry.SettingsType) EditorGUI.EnumPopup(_rect, entity.type); if (type != entity.type) { entity.type = type; switch (type) { case CVRAdvancedSettingsEntry.SettingsType.GameObjectToggle: entity.setting = new CVRAdvancesAvatarSettingGameObjectToggle(); break; case CVRAdvancedSettingsEntry.SettingsType.GameObjectDropdown: entity.setting = new CVRAdvancesAvatarSettingGameObjectDropdown(); break; case CVRAdvancedSettingsEntry.SettingsType.MaterialColor: entity.setting = new CVRAdvancedAvatarSettingMaterialColor(); break; case CVRAdvancedSettingsEntry.SettingsType.Slider: entity.setting = new CVRAdvancesAvatarSettingSlider(); break; case CVRAdvancedSettingsEntry.SettingsType.Joystick2D: entity.setting = new CVRAdvancesAvatarSettingJoystick2D(); break; case CVRAdvancedSettingsEntry.SettingsType.Joystick3D: entity.setting = new CVRAdvancesAvatarSettingJoystick3D(); break; case CVRAdvancedSettingsEntry.SettingsType.InputSingle: entity.setting = new CVRAdvancesAvatarSettingInputSingle(); break; case CVRAdvancedSettingsEntry.SettingsType.InputVector2: entity.setting = new CVRAdvancesAvatarSettingInputVector2(); break; case CVRAdvancedSettingsEntry.SettingsType.InputVector3: entity.setting = new CVRAdvancesAvatarSettingInputVector3(); break; } } rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight); if (entity.type == CVRAdvancedSettingsEntry.SettingsType.GameObjectToggle) { EditorGUI.LabelField(_rect, "Generate Type"); _rect.x += 100; _rect.width = rect.width - 100; entity.setting.usedType = (CVRAdvancesAvatarSettingBase.ParameterType) EditorGUI.EnumPopup(_rect, entity.setting.usedType); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight); } if (entity.type == CVRAdvancedSettingsEntry.SettingsType.GameObjectDropdown) { EditorGUI.LabelField(_rect, "Generate Type"); _rect.x += 100; _rect.width = rect.width - 100; entity.setting.usedType = (CVRAdvancesAvatarSettingBase.ParameterType) EditorGUI.IntPopup( _rect, (int) entity.setting.usedType, new string[]{"Generate Float", "Generate Int"}, new int[]{1, 2}); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight); } switch (entity.type) { case CVRAdvancedSettingsEntry.SettingsType.GameObjectToggle: animatorParameters.Add(entity.machineName); var gameObjectToggle = (CVRAdvancesAvatarSettingGameObjectToggle) entity.setting; // Default State EditorGUI.LabelField(_rect, "Default"); _rect.x += 100; _rect.width = rect.width - 100; gameObjectToggle.defaultValue = EditorGUI.Toggle(_rect, gameObjectToggle.defaultValue); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight); // Use Animation Clip EditorGUI.LabelField(_rect, "Use Animation"); _rect.x += 100; _rect.width = rect.width - 100; gameObjectToggle.useAnimationClip = EditorGUI.Toggle(_rect, gameObjectToggle.useAnimationClip); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; if (gameObjectToggle.useAnimationClip) { _rect = new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight); // Animation Clip Slot EditorGUI.LabelField(_rect, "Clip"); _rect.x += 100; _rect.width = rect.width - 100; gameObjectToggle.animationClip = (AnimationClip)EditorGUI.ObjectField(_rect, gameObjectToggle.animationClip, typeof(AnimationClip), true); } else { var gameObjectList = gameObjectToggle.GetReorderableList(_avatar); gameObjectList.DoList(new Rect(rect.x, rect.y, rect.width, 20f)); } break; case CVRAdvancedSettingsEntry.SettingsType.GameObjectDropdown: animatorParameters.Add(entity.machineName); var gameObjectDropdown = (CVRAdvancesAvatarSettingGameObjectDropdown) entity.setting; EditorGUI.LabelField(_rect, "Default"); _rect.x += 100; _rect.width = rect.width - 100; gameObjectDropdown.defaultValue = EditorGUI.Popup(_rect, gameObjectDropdown.defaultValue, gameObjectDropdown.getOptionsList()); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; var options = gameObjectDropdown.GetReorderableList(_avatar); options.DoList(new Rect(rect.x, rect.y, rect.width, 20f)); break; case CVRAdvancedSettingsEntry.SettingsType.MaterialColor: animatorParameters.Add(entity.machineName + "-r"); animatorParameters.Add(entity.machineName + "-g"); animatorParameters.Add(entity.machineName + "-b"); var materialColor = (CVRAdvancedAvatarSettingMaterialColor) entity.setting; EditorGUI.LabelField(_rect, "Default"); _rect.x += 100; _rect.width = rect.width - 100; materialColor.defaultValue = EditorGUI.ColorField(_rect, new GUIContent(), materialColor.defaultValue, true, false, false); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; var materialColorList = materialColor.GetReorderableList(_avatar); materialColorList.DoList(new Rect(rect.x, rect.y, rect.width, 20f)); break; case CVRAdvancedSettingsEntry.SettingsType.Slider: animatorParameters.Add(entity.machineName); var slider = (CVRAdvancesAvatarSettingSlider) entity.setting; EditorGUI.LabelField(_rect, "Default"); _rect.x += 100; _rect.width = rect.width - 100; slider.defaultValue = EditorGUI.Slider(_rect, slider.defaultValue, 0f, 1f); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight); // Use Animation Clip EditorGUI.LabelField(_rect, "Use Animation"); _rect.x += 100; _rect.width = rect.width - 100; slider.useAnimationClip = EditorGUI.Toggle(_rect, slider.useAnimationClip); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; if (slider.useAnimationClip) { _rect = new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight); //Min Animation Clip Slot EditorGUI.LabelField(_rect, "Min Clip"); _rect.x += 100; _rect.width = rect.width - 100; slider.minAnimationClip = (AnimationClip)EditorGUI.ObjectField(_rect, slider.minAnimationClip, typeof(AnimationClip), true); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight); //Max Animation Clip Slot EditorGUI.LabelField(_rect, "Max Clip"); _rect.x += 100; _rect.width = rect.width - 100; slider.maxAnimationClip = (AnimationClip)EditorGUI.ObjectField(_rect, slider.maxAnimationClip, typeof(AnimationClip), true); } else { var materialPropertyList = slider.GetReorderableList(_avatar); materialPropertyList.DoList(new Rect(rect.x, rect.y, rect.width, 20f)); } foreach (var target in slider.materialPropertyTargets) { rect.y += EditorGUIUtility.singleLineHeight * 1.25f * (!target.isCollapsed ? 1 : 5); } rect.y += EditorGUIUtility.singleLineHeight * (3f + (slider.materialPropertyTargets.Count == 0 ? 1.25f : 0)); _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight * 3); if (!slider.useAnimationClip) { EditorGUI.HelpBox(_rect, "The Setup Utility will help you create a slider for Material properties " + "If you want to bind other properties you can edit the animation files generated " + "by the System after the animator was created.", MessageType.Info); } break; case CVRAdvancedSettingsEntry.SettingsType.Joystick2D: animatorParameters.Add(entity.machineName + "-x"); animatorParameters.Add(entity.machineName + "-y"); var joystick = (CVRAdvancesAvatarSettingJoystick2D) entity.setting; _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight * 3); joystick.defaultValue = EditorGUI.Vector2Field(_rect, "Default", joystick.defaultValue); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight * 3); joystick.rangeMin = EditorGUI.Vector2Field(_rect, "Range Min", joystick.rangeMin); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight * 3); joystick.rangeMax = EditorGUI.Vector2Field(_rect, "Range Max", joystick.rangeMax); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight * 3); EditorGUI.HelpBox(_rect, "This Settings does not provide a Setup Utility. "+ "But it will create the necessary Animator Layers, Parameters and Animations. "+ "So you can edit them to your liking after the animator was created.", MessageType.Info); break; case CVRAdvancedSettingsEntry.SettingsType.Joystick3D: animatorParameters.Add(entity.machineName + "-x"); animatorParameters.Add(entity.machineName + "-y"); animatorParameters.Add(entity.machineName + "-z"); var joystick3D = (CVRAdvancesAvatarSettingJoystick3D) entity.setting; _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight * 3); joystick3D.defaultValue = EditorGUI.Vector3Field(_rect, "Default", joystick3D.defaultValue); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight * 3); joystick3D.rangeMin = EditorGUI.Vector2Field(_rect, "Range Min", joystick3D.rangeMin); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight * 3); joystick3D.rangeMax = EditorGUI.Vector2Field(_rect, "Range Max", joystick3D.rangeMax); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight * 3); EditorGUI.HelpBox(_rect, "This Settings does not provide a Setup Utility. "+ "But it will create the necessary Animator Layers, Parameters and Animations. "+ "So you can edit them to your liking after the animator was created.", MessageType.Info); break; case CVRAdvancedSettingsEntry.SettingsType.InputSingle: animatorParameters.Add(entity.machineName); var inputSingle = (CVRAdvancesAvatarSettingInputSingle) entity.setting; EditorGUI.LabelField(_rect, "Default"); _rect.x += 100; _rect.width = rect.width - 100; inputSingle.defaultValue = EditorGUI.FloatField(_rect, inputSingle.defaultValue); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight * 3); EditorGUI.HelpBox(_rect, "This Settings does not provide a Setup Utility. "+ "But it will create the necessary Animator Layers, Parameters and Animations. "+ "So you can edit them to your liking after the animator was created.", MessageType.Info); break; case CVRAdvancedSettingsEntry.SettingsType.InputVector2: animatorParameters.Add(entity.machineName + "-x"); animatorParameters.Add(entity.machineName + "-y"); var inputVector2 = (CVRAdvancesAvatarSettingInputVector2) entity.setting; _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight * 3); inputVector2.defaultValue = EditorGUI.Vector2Field(_rect, "Default", inputVector2.defaultValue); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight * 3); EditorGUI.HelpBox(_rect, "This Settings does not provide a Setup Utility. "+ "But it will create the necessary Animator Layers, Parameters and Animations. "+ "So you can edit them to your liking after the animator was created.", MessageType.Info); break; case CVRAdvancedSettingsEntry.SettingsType.InputVector3: animatorParameters.Add(entity.machineName + "-x"); animatorParameters.Add(entity.machineName + "-y"); animatorParameters.Add(entity.machineName + "-z"); var inputVector3 = (CVRAdvancesAvatarSettingInputVector3) entity.setting; _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight * 3); inputVector3.defaultValue = EditorGUI.Vector3Field(_rect, "Default", inputVector3.defaultValue); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight * 3); EditorGUI.HelpBox(_rect, "This Settings does not provide a Setup Utility. "+ "But it will create the necessary Animator Layers, Parameters and Animations. "+ "So you can edit them to your liking after the animator was created.", MessageType.Info); break; } } private void OnAdd(ReorderableList list) { _avatar.avatarSettings.settings.Add(new CVRAdvancedSettingsEntry()); Repaint(); } private void OnChanged(ReorderableList list) { //EditorUtility.SetDirty(target); } private float OnHeightElementTagging(int index) { if (index > _avatar.advancedTaggingList.Count) return EditorGUIUtility.singleLineHeight * 2.5f; return EditorGUIUtility.singleLineHeight * ((_avatar.advancedTaggingList[index].fallbackGameObject != null && _avatar.advancedTaggingList[index].fallbackGameObject.activeSelf) ? 5f : 3.75f); } private void OnDrawHeaderTagging(Rect rect) { Rect _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight); GUI.Label(_rect, "Tagged Gameobjects"); } private void OnDrawElementTagging(Rect rect, int index, bool isActive, bool isFocused) { if (index > _avatar.advancedTaggingList.Count) return; tagEntry = _avatar.advancedTaggingList[index]; rect.y += 2; rect.x += 12; rect.width -= 12; Rect _rect = new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight); EditorGUI.LabelField(_rect, "Tags"); _rect.x += 100; _rect.width = rect.width - 100; tagEntry.tags = (CVRAvatarAdvancedTaggingEntry.Tags) EditorGUI.EnumFlagsField(_rect, tagEntry.tags); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight); EditorGUI.LabelField(_rect, "GameObject"); _rect.x += 100; _rect.width = rect.width - 100; tagEntry.gameObject = (GameObject) EditorGUI.ObjectField(_rect, tagEntry.gameObject, typeof(GameObject), true); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight); EditorGUI.LabelField(_rect, "Fallback GO"); _rect.x += 100; _rect.width = rect.width - 100; tagEntry.fallbackGameObject = (GameObject) EditorGUI.ObjectField(_rect, tagEntry.fallbackGameObject, typeof(GameObject), true); rect.y += EditorGUIUtility.singleLineHeight * 1.25f; _rect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight); if (tagEntry.fallbackGameObject != null && tagEntry.fallbackGameObject.activeSelf) { EditorGUI.HelpBox(_rect, "The Fallback needs to be disabled by default!", MessageType.Error); } } private void OnAddTagging(ReorderableList list) { _avatar.advancedTaggingList.Add(new CVRAvatarAdvancedTaggingEntry()); Repaint(); } private void OnChangedTagging(ReorderableList list) { EditorUtility.SetDirty(target); } private static void CreateAvatarSettings(CVRAvatar avatar) { string[] guids = AssetDatabase.FindAssets("AvatarAnimator t:animatorController", null); if (guids.Length < 1) { Debug.LogError("No Animator controller with the name \"AvatarAnimator\" was found. Please make sure that you CCK is installed properly."); return; } Type projectWindowUtilType = typeof(ProjectWindowUtil); MethodInfo getActiveFolderPath = projectWindowUtilType.GetMethod("GetActiveFolderPath", BindingFlags.Static | BindingFlags.NonPublic); object obj = getActiveFolderPath.Invoke(null, new object[0]); string pathToCurrentFolder = obj.ToString(); avatar.avatarSettings = new CVRAdvancedAvatarSettings(); avatar.avatarSettings.baseController = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guids[0])); avatar.avatarSettings.settings = new List(); avatar.avatarSettings.initialized = true; } protected virtual void OnSceneGUI() { if (_avatar == null) _avatar = (CVRAvatar) target; if (_avatar != null) { var avatarTransform = _avatar.transform; var scale = avatarTransform.localScale; var inverseScale = new Vector3(1 / scale.x, 1 / scale.y, 1 / scale.z); //View Position GUIStyle style = new GUIStyle(); style.normal.textColor = Color.green; style.fontSize = 20; Handles.BeginGUI(); Vector3 pos = avatarTransform.TransformPoint(Vector3.Scale(_avatar.viewPosition, inverseScale)); Vector2 pos2D = HandleUtility.WorldToGUIPoint(pos); GUI.Label(new Rect(pos2D.x + 20, pos2D.y - 10, 100, 20), "View Position", style); Handles.EndGUI(); EditorGUI.BeginChangeCheck(); Vector3 viewPos = Handles.PositionHandle(pos, avatarTransform.rotation); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(_avatar, "CVR View Position Change"); _avatar.viewPosition = Vector3.Scale(avatarTransform.InverseTransformPoint(viewPos), scale); } //Voice Position style.normal.textColor = Color.red; Handles.BeginGUI(); pos = avatarTransform.TransformPoint(Vector3.Scale(_avatar.voicePosition, inverseScale)); pos2D = HandleUtility.WorldToGUIPoint(pos); GUI.Label(new Rect(pos2D.x + 20, pos2D.y - 10, 100, 20), "Voice Position", style); Handles.EndGUI(); EditorGUI.BeginChangeCheck(); Vector3 voicePos = Handles.PositionHandle(pos, avatarTransform.rotation); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(_avatar, "CVR Voice Position Change"); _avatar.voicePosition = Vector3.Scale(avatarTransform.InverseTransformPoint(voicePos), scale); } } } void GetBlendShapeNames() { if (_avatar.bodyMesh != null) { _blendShapeNames = new List(); _blendShapeNames.Add("-none-"); for (int i = 0; i < _avatar.bodyMesh.sharedMesh.blendShapeCount; ++i) _blendShapeNames.Add(_avatar.bodyMesh.sharedMesh.GetBlendShapeName(i)); } else { _blendShapeNames = new List(); _blendShapeNames.Add("-none-"); } } void FindVisemes() { for (int i = 0; i < _visemeNames.Length; i++) { for (int j = 0; j < _blendShapeNames.Count; ++j) { if (_blendShapeNames[j].ToLower().Contains("v_" + _visemeNames[i].ToLower()) || _blendShapeNames[j].ToLower().Contains("viseme_" + _visemeNames[i].ToLower())) { _avatar.visemeBlendshapes[i] = _blendShapeNames[j]; } } } } } }