diff options
author | tylermurphy534 <tylermurphy534@gmail.com> | 2022-11-06 15:12:42 -0500 |
---|---|---|
committer | tylermurphy534 <tylermurphy534@gmail.com> | 2022-11-06 15:12:42 -0500 |
commit | eb84bb298d2b95aec7b2ae12cbf25ac64f25379a (patch) | |
tree | efd616a157df06ab661c6d56651853431ac6b08b /VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor | |
download | unityprojects-eb84bb298d2b95aec7b2ae12cbf25ac64f25379a.tar.gz unityprojects-eb84bb298d2b95aec7b2ae12cbf25ac64f25379a.tar.bz2 unityprojects-eb84bb298d2b95aec7b2ae12cbf25ac64f25379a.zip |
move to self host
Diffstat (limited to 'VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor')
121 files changed, 12429 insertions, 0 deletions
diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline.meta new file mode 100644 index 00000000..882a6944 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 156796d8b8fd7424fb8c391b51c059bf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline/Samples.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline/Samples.meta new file mode 100644 index 00000000..9916f188 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline/Samples.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5661c4d32bccbc047826fc30ccbcea3e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline/Samples/VRCSDKBuildRequestedCallbackSample.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline/Samples/VRCSDKBuildRequestedCallbackSample.cs new file mode 100644 index 00000000..80f026e2 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline/Samples/VRCSDKBuildRequestedCallbackSample.cs @@ -0,0 +1,18 @@ +#if VRC_SDK_PIPELINE_SAMPLES + +using UnityEditor; + +namespace VRC.SDKBase.Editor.BuildPipeline.Samples +{ + public class VRCSDKBuildRequestedCallbackSample : IVRCSDKBuildRequestedCallback + { + public int callbackOrder => 0; + + public bool OnBuildRequested(VRCSDKRequestedBuildType requestedBuildType) + { + return EditorUtility.DisplayDialog("Build Confirmation", "Are you sure you want to build?", "Yes", "Not Yes"); + } + } +} + +#endif diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline/Samples/VRCSDKBuildRequestedCallbackSample.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline/Samples/VRCSDKBuildRequestedCallbackSample.cs.meta new file mode 100644 index 00000000..1b52ab1e --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline/Samples/VRCSDKBuildRequestedCallbackSample.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0a1d20f4241085e46bdddc71b691465b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline/VRC.SDKBase.Editor.BuildPipeline.asmdef b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline/VRC.SDKBase.Editor.BuildPipeline.asmdef new file mode 100644 index 00000000..a59fc7d6 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline/VRC.SDKBase.Editor.BuildPipeline.asmdef @@ -0,0 +1,12 @@ +{ + "name": "VRC.SDKBase.Editor.BuildPipeline", + "references": [], + "optionalUnityReferences": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [] +}
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline/VRC.SDKBase.Editor.BuildPipeline.asmdef.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline/VRC.SDKBase.Editor.BuildPipeline.asmdef.meta new file mode 100644 index 00000000..ec3710a4 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/BuildPipeline/VRC.SDKBase.Editor.BuildPipeline.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 21332e1f0d937794d916d2402ba1943a +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components.meta new file mode 100644 index 00000000..b1fd960e --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cc7ba71f06619ae4295d07b53f15e0b3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/ApiCacheEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/ApiCacheEditor.cs new file mode 100644 index 00000000..297fc8fb --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/ApiCacheEditor.cs @@ -0,0 +1,19 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEditor; +using VRC.Core; + +[CustomEditor(typeof(ApiCache))] +public class ApiCacheEditor : Editor { + public override void OnInspectorGUI() + { + foreach (System.Type type in ApiCache.cache.Keys) + { + Dictionary<string, ApiCache.CacheEntry> typeCache = ApiCache.cache[type]; + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PrefixLabel(type.Name); + EditorGUILayout.LabelField(typeCache.Count.ToString()); + EditorGUILayout.EndHorizontal(); + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/ApiCacheEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/ApiCacheEditor.cs.meta new file mode 100644 index 00000000..7c1cdd09 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/ApiCacheEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 39cdf3092ab81be4b9e623cb5a8819d8 +timeCreated: 1509575680 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EditorCoroutine.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EditorCoroutine.cs new file mode 100644 index 00000000..8363d450 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EditorCoroutine.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using Object = UnityEngine.Object; + +public class EditorCoroutine +{ + public static EditorCoroutine Start( IEnumerator _routine ) + { + EditorCoroutine coroutine = new EditorCoroutine(_routine); + coroutine.start(); + return coroutine; + } + + + public static EditorCoroutine Start(System.Action _action) + { + EditorCoroutine coroutine = new EditorCoroutine(_action); + coroutine.start(); + return coroutine; + } + + readonly IEnumerator routine; + EditorCoroutine( IEnumerator _routine ) + { + routine = _routine; + } + + readonly System.Action action; + EditorCoroutine(System.Action _action) + { + action = _action; + } + + void start() + { + EditorApplication.update += update; + } + public void stop() + { + EditorApplication.update -= update; + } + + void update() + { + if (routine != null) + { + if (!routine.MoveNext()) + stop(); + } + else if (action != null) + { + action(); + stop(); + } + else + stop(); + + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EditorCoroutine.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EditorCoroutine.cs.meta new file mode 100644 index 00000000..dc452288 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EditorCoroutine.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 89005ebc9543e0a4284893c09ca19b1d +timeCreated: 1473271738 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EditorHandling.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EditorHandling.cs new file mode 100644 index 00000000..32923b58 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EditorHandling.cs @@ -0,0 +1,17 @@ +using UnityEditor; +using UnityEngine.SceneManagement; + +[InitializeOnLoad] +public static class EditorHandling +{ + static EditorHandling() + { + UnityEditor.SceneManagement.EditorSceneManager.sceneOpened += SceneOpenedCallback; + } + + static void SceneOpenedCallback( Scene scene, UnityEditor.SceneManagement.OpenSceneMode mode) + { + // refresh window when scene is opened to display content images correctly + if (null != VRCSdkControlPanel.window) VRCSdkControlPanel.window.Reset(); + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EditorHandling.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EditorHandling.cs.meta new file mode 100644 index 00000000..7657e22a --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EditorHandling.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3d6c2e367eaa9564ebf6267ec163cfbd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EventHandlerEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EventHandlerEditor.cs new file mode 100644 index 00000000..fcca3092 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EventHandlerEditor.cs @@ -0,0 +1,358 @@ +#if UNITY_EDITOR + +using UnityEngine; +using UnityEditor; +using UnityEditor.SceneManagement; +using System.Collections.Generic; +using System.Linq; +using VRC.SDKBase; + +namespace VRCSDK2 +{ +#if VRC_SDK_VRCSDK2 + [CustomEditor(typeof(VRCSDK2.VRC_EventHandler))] + public class EventHandlerEditor : UnityEditor.Editor + { + bool showDeferredEvents = false; + + static VRCSDK2.VRC_EventHandler.VrcEventType lastAddedEventType = VRCSDK2.VRC_EventHandler.VrcEventType.SendMessage; + + public override void OnInspectorGUI() + { + VRCSDK2.VRC_EventHandler myTarget = (VRCSDK2.VRC_EventHandler)target; + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("ID:"); + EditorGUILayout.EndHorizontal(); + + if (myTarget.GetComponent<VRCSDK2.VRC_Trigger>() != null) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Add Events via the VRC_Trigger on this object."); + EditorGUILayout.EndHorizontal(); + } + else + { + EditorGUI.BeginChangeCheck(); + + RenderOldEditor(myTarget); + + if (EditorGUI.EndChangeCheck()) + EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); + } + + if (myTarget.deferredEvents.Count > 0) + { + showDeferredEvents = EditorGUILayout.Foldout(showDeferredEvents, "Deferred Events"); + if (showDeferredEvents) + RenderEvents(myTarget.deferredEvents); + } + } + + int[] sendMessageMethodIndicies; + private void RenderOldEditor(VRCSDK2.VRC_EventHandler myTarget) + { + EditorGUILayout.HelpBox("Please use a VRC_Trigger in the future.", MessageType.Error); + + if (GUILayout.Button("Add Event Handler")) + myTarget.Events.Add(new VRCSDK2.VRC_EventHandler.VrcEvent()); + + bool first = true; + int deleteEventIndex = -1; + if (sendMessageMethodIndicies == null || sendMessageMethodIndicies.Length != myTarget.Events.Count) + sendMessageMethodIndicies = new int[myTarget.Events.Count + 1]; + + for (int i = 0; i < myTarget.Events.Count; ++i) + { + if (!first) + EditorGUILayout.Separator(); + first = false; + + EditorGUILayout.LabelField("Event " + (i + 1).ToString()); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Event Name"); + myTarget.Events[i].Name = EditorGUILayout.TextField(myTarget.Events[i].Name); + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Event Type"); + myTarget.Events[i].EventType = (VRCSDK2.VRC_EventHandler.VrcEventType)EditorGUILayout.EnumPopup(myTarget.Events[i].EventType); + EditorGUILayout.EndHorizontal(); + + switch (myTarget.Events[i].EventType) + { + case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationBool: + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Variable"); + myTarget.Events[i].ParameterString = EditorGUILayout.TextField(myTarget.Events[i].ParameterString); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Operation"); + myTarget.Events[i].ParameterBoolOp = (VRCSDK2.VRC_EventHandler.VrcBooleanOp)EditorGUILayout.EnumPopup(myTarget.Events[i].ParameterBoolOp); + EditorGUILayout.EndHorizontal(); + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationFloat: + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Variable"); + myTarget.Events[i].ParameterString = EditorGUILayout.TextField(myTarget.Events[i].ParameterString); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Value"); + myTarget.Events[i].ParameterFloat = EditorGUILayout.FloatField(myTarget.Events[i].ParameterFloat); + EditorGUILayout.EndHorizontal(); + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationTrigger: + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Trigger"); + myTarget.Events[i].ParameterString = EditorGUILayout.TextField(myTarget.Events[i].ParameterString); + EditorGUILayout.EndHorizontal(); + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.AudioTrigger: + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("AudioSource"); + myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true); + EditorGUILayout.EndHorizontal(); + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.MeshVisibility: + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Mesh"); + myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Operation"); + myTarget.Events[i].ParameterBoolOp = (VRCSDK2.VRC_EventHandler.VrcBooleanOp)EditorGUILayout.EnumPopup(myTarget.Events[i].ParameterBoolOp); + EditorGUILayout.EndHorizontal(); + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.PlayAnimation: + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Target"); + myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Animation"); + myTarget.Events[i].ParameterString = EditorGUILayout.TextField(myTarget.Events[i].ParameterString); + EditorGUILayout.EndHorizontal(); + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.RunConsoleCommand: + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Command"); + myTarget.Events[i].ParameterString = EditorGUILayout.TextField(myTarget.Events[i].ParameterString); + EditorGUILayout.EndHorizontal(); + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.SendMessage: + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Receiver"); + myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Message"); + + // sorry for this shit show. Below allows us to show a list of public methods, but also allow custom messages + var methods = VRC_EditorTools.GetAccessibleMethodsOnGameObject(myTarget.Events[i].ParameterObject); + List<string> methodList = methods.Values.Aggregate(new List<string>(), (acc, lst) => { acc.AddRange(lst.Select(mi => mi.Name)); return acc; }); + methodList.Add("Custom Message"); + + string[] _choices = methodList.ToArray(); + + int currentIndex = methodList.Count - 1; + + if (methodList.Contains(myTarget.Events[i].ParameterString)) + currentIndex = methodList.IndexOf(myTarget.Events[i].ParameterString); + + sendMessageMethodIndicies[i] = EditorGUILayout.Popup(currentIndex, _choices); + + if (sendMessageMethodIndicies[i] != methodList.Count - 1) + { + myTarget.Events[i].ParameterString = _choices[sendMessageMethodIndicies[i]]; + } + else + { + if (methodList.Contains(myTarget.Events[i].ParameterString)) + myTarget.Events[i].ParameterString = ""; + + myTarget.Events[i].ParameterString = EditorGUILayout.TextField(myTarget.Events[i].ParameterString); + } + + EditorGUILayout.EndHorizontal(); + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.SetGameObjectActive: + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("GameObject"); + myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Operation"); + myTarget.Events[i].ParameterBoolOp = (VRCSDK2.VRC_EventHandler.VrcBooleanOp)EditorGUILayout.EnumPopup(myTarget.Events[i].ParameterBoolOp); + EditorGUILayout.EndHorizontal(); + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.SetParticlePlaying: + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Target"); + myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Operation"); + myTarget.Events[i].ParameterBoolOp = (VRCSDK2.VRC_EventHandler.VrcBooleanOp)EditorGUILayout.EnumPopup(myTarget.Events[i].ParameterBoolOp); + EditorGUILayout.EndHorizontal(); + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.TeleportPlayer: + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Location"); + myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Align Room To Destination"); + myTarget.Events[i].ParameterBoolOp = (VRCSDK2.VRC_EventHandler.VrcBooleanOp)EditorGUILayout.EnumPopup(myTarget.Events[i].ParameterBoolOp); + EditorGUILayout.EndHorizontal(); + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.SetWebPanelURI: + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("URI"); + myTarget.Events[i].ParameterString = EditorGUILayout.TextField(myTarget.Events[i].ParameterString); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Panel"); + myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true); + EditorGUILayout.EndHorizontal(); + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.SetWebPanelVolume: + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Volume"); + myTarget.Events[i].ParameterFloat = EditorGUILayout.FloatField(myTarget.Events[i].ParameterFloat); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Panel"); + myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true); + EditorGUILayout.EndHorizontal(); + break; + default: + EditorGUILayout.BeginHorizontal(); + GUIStyle redText = new GUIStyle(); + redText.normal.textColor = Color.red; + EditorGUILayout.LabelField("Unsupported event type", redText); + EditorGUILayout.EndHorizontal(); + break; + } + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Delete " + myTarget.Events[i].Name + "?"); + if (GUILayout.Button("delete")) + deleteEventIndex = i; + EditorGUILayout.EndHorizontal(); + + if (myTarget.Events[i].ParameterObject == null) + myTarget.Events[i].ParameterObject = myTarget.gameObject; + } + + + if (deleteEventIndex != -1) + myTarget.Events.RemoveAt(deleteEventIndex); + } + + private void RenderEvents(IEnumerable<VRCSDK2.VRC_EventHandler.EventInfo> entries) + { + foreach (VRCSDK2.VRC_EventHandler.EventInfo entry in entries) + { + EditorGUILayout.PrefixLabel("Target"); + EditorGUILayout.ObjectField(entry.evt.ParameterObject, typeof(GameObject), true); + + EditorGUILayout.LabelField(string.Format("Name: {0}", entry.evt.Name)); + EditorGUILayout.LabelField(string.Format("Type: {0}", entry.evt.EventType)); + EditorGUILayout.LabelField(string.Format("Bool: {0}", entry.evt.ParameterBool)); + EditorGUILayout.LabelField(string.Format("Float: {0}", entry.evt.ParameterFloat)); + EditorGUILayout.LabelField(string.Format("Int: {0}", entry.evt.ParameterInt)); + EditorGUILayout.LabelField(string.Format("String: {0}", entry.evt.ParameterString)); + + EditorGUILayout.Space(); + } + } + + public static void RenderEditor(VRCSDK2.VRC_EventHandler myTarget) + { + bool first = true; + int deleteEventIndex = -1; + + for (int i = 0; i < myTarget.Events.Count; ++i) + { + if (!first) + EditorGUILayout.Separator(); + first = false; + + if (RenderEventHeader(myTarget, myTarget.Events[i])) + deleteEventIndex = i; + + RenderEventHeader(myTarget, myTarget.Events[i]); + + if (myTarget.Events[i].ParameterObject == null) + myTarget.Events[i].ParameterObject = myTarget.gameObject; + } + + if (deleteEventIndex != -1) + myTarget.Events.RemoveAt(deleteEventIndex); + } + + public static VRCSDK2.VRC_EventHandler.VrcEvent RenderAddEvent(VRCSDK2.VRC_EventHandler myTarget) + { + VRCSDK2.VRC_EventHandler.VrcEvent newEvent = null; + + EditorGUILayout.BeginHorizontal(); + lastAddedEventType = VRC_EditorTools.FilteredEnumPopup("New Event Type", lastAddedEventType, (v) => v != VRCSDK2.VRC_EventHandler.VrcEventType.SpawnObject && v != VRCSDK2.VRC_EventHandler.VrcEventType.SendMessage); + if (GUILayout.Button("Add")) + { + newEvent = new VRCSDK2.VRC_EventHandler.VrcEvent + { + EventType = lastAddedEventType, + ParameterObject = myTarget.gameObject + }; + myTarget.Events.Add(newEvent); + EditorUtility.SetDirty(myTarget); + } + EditorGUILayout.EndHorizontal(); + + return newEvent; + } + + public static bool RenderEventHeader(VRCSDK2.VRC_EventHandler myTarget, VRCSDK2.VRC_EventHandler.VrcEvent evt) + { + EditorGUILayout.BeginHorizontal(); + evt.EventType = VRC_EditorTools.FilteredEnumPopup("New Event Type", evt.EventType, (v) => v != VRCSDK2.VRC_EventHandler.VrcEventType.SpawnObject && v != VRCSDK2.VRC_EventHandler.VrcEventType.SendMessage); + bool delete = GUILayout.Button("Remove"); + EditorGUILayout.EndHorizontal(); + + return delete; + } + } + + [CustomEditor(typeof(VRC.SDKBase.VRC_EventHandler))] + public class SDKBaseEventHandlerEditor : UnityEditor.Editor + { + public override void OnInspectorGUI() + { + EditorGUILayout.LabelField("Event Handlers are not supported in VRCSDK3."); + if (GUILayout.Button("replace me with the correct VRC_EventHandler")) + { + var go = ((VRC.SDKBase.VRC_EventHandler)target).gameObject; + DestroyImmediate(target); + go.AddComponent<VRCSDK2.VRC_EventHandler>(); + } + } + } +#else + + [CustomEditor(typeof(VRC.SDKBase.VRC_EventHandler))] + public class SDKBaseEventHandlerEditor : UnityEditor.Editor + { + public override void OnInspectorGUI() + { + EditorGUILayout.LabelField("Event Handlers are not supported in VRCSDK3."); + if( GUILayout.Button("delete me") ) + DestroyImmediate(target); + } + } + +#endif + + +} +#endif diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EventHandlerEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EventHandlerEditor.cs.meta new file mode 100644 index 00000000..d0632d47 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/EventHandlerEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4810e652e8242384c834320970702290 +timeCreated: 1454469344 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/OldTriggerEditors.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/OldTriggerEditors.cs new file mode 100644 index 00000000..ab085ca3 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/OldTriggerEditors.cs @@ -0,0 +1,48 @@ +#if VRC_SDK_VRCSDK2 && UNITY_EDITOR + +#pragma warning disable 0618 + +using UnityEditor; +using System.Collections; + +namespace VRCSDK2 +{ + [CustomEditor(typeof(VRCSDK2.VRC_KeyEvents))] + public class VRC_KeyEventsEditor : UnityEditor.Editor + { + public override void OnInspectorGUI() + { + EditorGUILayout.HelpBox("Obsolete. Please use a VRC_Trigger instead.", MessageType.Error); + } + } + + [CustomEditor(typeof(VRCSDK2.VRC_UseEvents))] + public class VRC_UseEventsEditor : UnityEditor.Editor + { + public override void OnInspectorGUI() + { + EditorGUILayout.HelpBox("Obsolete. Please use a VRC_Trigger instead.", MessageType.Error); + } + } + + [CustomEditor(typeof(VRCSDK2.VRC_TriggerColliderEventTrigger))] + public class VRC_TriggerColliderEventTriggerEditor : UnityEditor.Editor + { + public override void OnInspectorGUI() + { + EditorGUILayout.HelpBox("Obsolete. Please use a VRC_Trigger instead.", MessageType.Error); + } + } + + [CustomEditor(typeof(VRCSDK2.VRC_TimedEvents))] + public class VRC_TimedEventsEditor : UnityEditor.Editor + { + public override void OnInspectorGUI() + { + EditorGUILayout.HelpBox("Obsolete. Please use a VRC_Trigger instead.", MessageType.Error); + } + } +} + +#pragma warning restore 0618 +#endif
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/OldTriggerEditors.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/OldTriggerEditors.cs.meta new file mode 100644 index 00000000..d3b115e7 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/OldTriggerEditors.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 482185bf29f12074dada194ffef6a682 +timeCreated: 1475877803 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCAvatarDescriptorEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCAvatarDescriptorEditor.cs new file mode 100644 index 00000000..c248f212 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCAvatarDescriptorEditor.cs @@ -0,0 +1,225 @@ +#if VRC_SDK_VRCSDK2 +using UnityEngine; +using UnityEditor; +using System.Collections; +using System.Collections.Generic; +using VRC.SDK3.Editor; +using VRC.SDKBase.Editor; + +[CustomEditor(typeof(VRCSDK2.VRC_AvatarDescriptor))] +public class AvatarDescriptorEditor : Editor +{ + VRCSDK2.VRC_AvatarDescriptor avatarDescriptor; + VRC.Core.PipelineManager pipelineManager; + + SkinnedMeshRenderer selectedMesh; + List<string> blendShapeNames = null; + + bool shouldRefreshVisemes = false; + + public override void OnInspectorGUI() + { + if (avatarDescriptor == null) + avatarDescriptor = (VRCSDK2.VRC_AvatarDescriptor)target; + + if (pipelineManager == null) + { + pipelineManager = avatarDescriptor.GetComponent<VRC.Core.PipelineManager>(); + if (pipelineManager == null) + avatarDescriptor.gameObject.AddComponent<VRC.Core.PipelineManager>(); + } + + // DrawDefaultInspector(); + + if(VRCSdkControlPanel.window != null) + { + if( GUILayout.Button( "Select this avatar in the SDK control panel" ) ) + VRCSdkControlPanelAvatarBuilder.SelectAvatar(avatarDescriptor); + } + + avatarDescriptor.ViewPosition = EditorGUILayout.Vector3Field("View Position", avatarDescriptor.ViewPosition); + //avatarDescriptor.Name = EditorGUILayout.TextField("Avatar Name", avatarDescriptor.Name); + avatarDescriptor.Animations = (VRCSDK2.VRC_AvatarDescriptor.AnimationSet)EditorGUILayout.EnumPopup("Default Animation Set", avatarDescriptor.Animations); + avatarDescriptor.CustomStandingAnims = (AnimatorOverrideController)EditorGUILayout.ObjectField("Custom Standing Anims", avatarDescriptor.CustomStandingAnims, typeof(AnimatorOverrideController), true, null); + avatarDescriptor.CustomSittingAnims = (AnimatorOverrideController)EditorGUILayout.ObjectField("Custom Sitting Anims", avatarDescriptor.CustomSittingAnims, typeof(AnimatorOverrideController), true, null); + avatarDescriptor.ScaleIPD = EditorGUILayout.Toggle("Scale IPD", avatarDescriptor.ScaleIPD); + + avatarDescriptor.lipSync = (VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle)EditorGUILayout.EnumPopup("Lip Sync", avatarDescriptor.lipSync); + switch (avatarDescriptor.lipSync) + { + case VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.Default: + if (GUILayout.Button("Auto Detect!")) + AutoDetectLipSync(); + break; + + case VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.JawFlapBlendShape: + avatarDescriptor.VisemeSkinnedMesh = (SkinnedMeshRenderer)EditorGUILayout.ObjectField("Face Mesh", avatarDescriptor.VisemeSkinnedMesh, typeof(SkinnedMeshRenderer), true); + if (avatarDescriptor.VisemeSkinnedMesh != null) + { + DetermineBlendShapeNames(); + + int current = -1; + for (int b = 0; b < blendShapeNames.Count; ++b) + if (avatarDescriptor.MouthOpenBlendShapeName == blendShapeNames[b]) + current = b; + + string title = "Jaw Flap Blend Shape"; + int next = EditorGUILayout.Popup(title, current, blendShapeNames.ToArray()); + if (next >= 0) + avatarDescriptor.MouthOpenBlendShapeName = blendShapeNames[next]; + } + break; + + case VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.JawFlapBone: + avatarDescriptor.lipSyncJawBone = (Transform)EditorGUILayout.ObjectField("Jaw Bone", avatarDescriptor.lipSyncJawBone, typeof(Transform), true); + break; + + case VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.VisemeBlendShape: + SkinnedMeshRenderer prev = avatarDescriptor.VisemeSkinnedMesh; + avatarDescriptor.VisemeSkinnedMesh = (SkinnedMeshRenderer)EditorGUILayout.ObjectField("Face Mesh", avatarDescriptor.VisemeSkinnedMesh, typeof(SkinnedMeshRenderer), true); + if (avatarDescriptor.VisemeSkinnedMesh != prev) + shouldRefreshVisemes = true; + if (avatarDescriptor.VisemeSkinnedMesh != null) + { + DetermineBlendShapeNames(); + + if (avatarDescriptor.VisemeBlendShapes == null || avatarDescriptor.VisemeBlendShapes.Length != (int)VRCSDK2.VRC_AvatarDescriptor.Viseme.Count) + avatarDescriptor.VisemeBlendShapes = new string[(int)VRCSDK2.VRC_AvatarDescriptor.Viseme.Count]; + for (int i = 0; i < (int)VRCSDK2.VRC_AvatarDescriptor.Viseme.Count; ++i) + { + int current = -1; + for (int b = 0; b < blendShapeNames.Count; ++b) + if (avatarDescriptor.VisemeBlendShapes[i] == blendShapeNames[b]) + current = b; + + string title = "Viseme: " + ((VRCSDK2.VRC_AvatarDescriptor.Viseme)i).ToString(); + int next = EditorGUILayout.Popup(title, current, blendShapeNames.ToArray()); + if (next >= 0) + avatarDescriptor.VisemeBlendShapes[i] = blendShapeNames[next]; + } + + if (shouldRefreshVisemes) + AutoDetectVisemes(); + } + break; + } + EditorGUILayout.LabelField("Unity Version", avatarDescriptor.unityVersion); + } + + void DetermineBlendShapeNames() + { + if (avatarDescriptor.VisemeSkinnedMesh != null && + avatarDescriptor.VisemeSkinnedMesh != selectedMesh) + { + blendShapeNames = new List<string>(); + blendShapeNames.Add("-none-"); + selectedMesh = avatarDescriptor.VisemeSkinnedMesh; + if ((selectedMesh != null) && (selectedMesh.sharedMesh != null)) + { + for (int i = 0; i < selectedMesh.sharedMesh.blendShapeCount; ++i) + blendShapeNames.Add(selectedMesh.sharedMesh.GetBlendShapeName(i)); + } + } + } + + void AutoDetectVisemes() + { + + // prioritize strict - but fallback to looser - naming and don't touch user-overrides + + List<string> blendShapes = new List<string>(blendShapeNames); + blendShapes.Remove("-none-"); + + for (int v = 0; v < avatarDescriptor.VisemeBlendShapes.Length; v++) + { + if (string.IsNullOrEmpty(avatarDescriptor.VisemeBlendShapes[v])) + { + string viseme = ((VRCSDK2.VRC_AvatarDescriptor.Viseme)v).ToString().ToLowerInvariant(); + + foreach (string s in blendShapes) + { + if (s.ToLowerInvariant() == "vrc.v_" + viseme) + { + avatarDescriptor.VisemeBlendShapes[v] = s; + goto next; + } + } + foreach (string s in blendShapes) + { + if (s.ToLowerInvariant() == "v_" + viseme) + { + avatarDescriptor.VisemeBlendShapes[v] = s; + goto next; + } + } + foreach (string s in blendShapes) + { + if (s.ToLowerInvariant().EndsWith(viseme)) + { + avatarDescriptor.VisemeBlendShapes[v] = s; + goto next; + } + } + foreach (string s in blendShapes) + { + if (s.ToLowerInvariant() == viseme) + { + avatarDescriptor.VisemeBlendShapes[v] = s; + goto next; + } + } + foreach (string s in blendShapes) + { + if (s.ToLowerInvariant().Contains(viseme)) + { + avatarDescriptor.VisemeBlendShapes[v] = s; + goto next; + } + } + next: { } + } + } + + shouldRefreshVisemes = false; + + } + + void AutoDetectLipSync() + { + var smrs = avatarDescriptor.GetComponentsInChildren<SkinnedMeshRenderer>(); + foreach (var smr in smrs) + { + if (smr.sharedMesh.blendShapeCount > 0) + { + avatarDescriptor.lipSyncJawBone = null; + + if (smr.sharedMesh.blendShapeCount > 1) + { + avatarDescriptor.lipSync = VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.VisemeBlendShape; + avatarDescriptor.VisemeSkinnedMesh = smr; + shouldRefreshVisemes = true; + } + else + { + avatarDescriptor.lipSync = VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.JawFlapBlendShape; + avatarDescriptor.VisemeSkinnedMesh = null; + } + + return; + } + } + + Animator a = avatarDescriptor.GetComponent<Animator>(); + if (!a) + EditorUtility.DisplayDialog("Ooops", "This avatar has no Animator and can have no lipsync.", "OK"); + else if (a.GetBoneTransform(HumanBodyBones.Jaw) != null) + { + avatarDescriptor.lipSync = VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.JawFlapBone; + avatarDescriptor.lipSyncJawBone = avatarDescriptor.GetComponent<Animator>().GetBoneTransform(HumanBodyBones.Jaw); + avatarDescriptor.VisemeSkinnedMesh = null; + return; + } + + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCAvatarDescriptorEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCAvatarDescriptorEditor.cs.meta new file mode 100644 index 00000000..efb9de93 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCAvatarDescriptorEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5e83254bb97e84795ac882692ae124ba +timeCreated: 1450462624 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCObjectSpawnEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCObjectSpawnEditor.cs new file mode 100644 index 00000000..ab194e3b --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCObjectSpawnEditor.cs @@ -0,0 +1,23 @@ +#if VRC_SDK_VRCSDK2 +using UnityEngine; +using System.Collections; +using UnityEditor; +using System; + +[CustomEditor(typeof(VRCSDK2.VRC_ObjectSpawn))] +public class VRCObjectSpawnEditor : Editor +{ + VRCSDK2.VRC_ObjectSpawn spawn; + + void OnEnable() + { + if (spawn == null) + spawn = (VRCSDK2.VRC_ObjectSpawn)target; + } + + public override void OnInspectorGUI() + { + DrawDefaultInspector(); + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCObjectSpawnEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCObjectSpawnEditor.cs.meta new file mode 100644 index 00000000..9e238711 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCObjectSpawnEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 26a75599848adb449b7aceed5090e35c +timeCreated: 1463516633 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCObjectSyncEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCObjectSyncEditor.cs new file mode 100644 index 00000000..4272f049 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCObjectSyncEditor.cs @@ -0,0 +1,25 @@ +#if VRC_SDK_VRCSDK2 + +using UnityEngine; +using System.Collections; +using UnityEditor; +using System; + +[CustomEditor(typeof(VRCSDK2.VRC_ObjectSync))] +public class VRCObjectSyncEditor : Editor +{ + VRCSDK2.VRC_ObjectSync sync; + + void OnEnable() + { + if (sync == null) + sync = (VRCSDK2.VRC_ObjectSync)target; + } + + public override void OnInspectorGUI() + { + sync.SynchronizePhysics = EditorGUILayout.Toggle("Synchronize Physics",sync.SynchronizePhysics); + sync.AllowCollisionTransfer = EditorGUILayout.Toggle("Allow Collision Transfer", sync.AllowCollisionTransfer); + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCObjectSyncEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCObjectSyncEditor.cs.meta new file mode 100644 index 00000000..c95d4e32 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCObjectSyncEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ed4aad2698d3b62408e69b57c7748791 +timeCreated: 1463516212 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerModEditorWindow.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerModEditorWindow.cs new file mode 100644 index 00000000..693cd368 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerModEditorWindow.cs @@ -0,0 +1,37 @@ +#if VRC_SDK_VRCSDK2 + +using UnityEngine; +using UnityEditor; + +public class VRCPlayerModEditorWindow : EditorWindow { + + public delegate void AddModCallback(); + public static AddModCallback addModCallback; + + private static VRCSDK2.VRC_PlayerMods myTarget; + + private static VRCSDK2.VRCPlayerModFactory.PlayerModType type; + + public static void Init (VRCSDK2.VRC_PlayerMods target, AddModCallback callback) + { + // Get existing open window or if none, make a new one: + EditorWindow.GetWindow (typeof (VRCPlayerModEditorWindow)); + addModCallback = callback; + myTarget = target; + + type = VRCSDK2.VRCPlayerModFactory.PlayerModType.Jump; + } + + void OnGUI () + { + type = (VRCSDK2.VRCPlayerModFactory.PlayerModType)EditorGUILayout.EnumPopup("Mods", type); + if(GUILayout.Button("Add Mod")) + { + VRCSDK2.VRCPlayerMod mod = VRCSDK2.VRCPlayerModFactory.Create(type); + myTarget.AddMod(mod); + addModCallback(); + } + } +} + +#endif
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerModEditorWindow.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerModEditorWindow.cs.meta new file mode 100644 index 00000000..e43182bd --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerModEditorWindow.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 8986a640e24a0754ea0aded12234b808 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerModsEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerModsEditor.cs new file mode 100644 index 00000000..5efaa351 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerModsEditor.cs @@ -0,0 +1,109 @@ +#if VRC_SDK_VRCSDK2 +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using UnityEditor; +using System; + +namespace VRCSDK2 +{ + [CustomEditor(typeof(VRCSDK2.VRC_PlayerMods))] + public class VRCPlayerModsEditor : UnityEditor.Editor + { + VRCSDK2.VRC_PlayerMods myTarget; + + void OnEnable() + { + if(myTarget == null) + myTarget = (VRCSDK2.VRC_PlayerMods)target; + } + + public override void OnInspectorGUI() + { + myTarget.isRoomPlayerMods = EditorGUILayout.Toggle("isRoomPlayerMods", myTarget.isRoomPlayerMods); + + List<VRCSDK2.VRCPlayerMod> playerMods = myTarget.playerMods; + for(int i=0; i<playerMods.Count; ++i) + { + VRCSDK2.VRCPlayerMod mod = playerMods[i]; + EditorGUILayout.BeginVertical("box"); + EditorGUILayout.LabelField(mod.name, EditorStyles.boldLabel); + if( mod.allowNameEdit ) + mod.name = EditorGUILayout.TextField( "Mod Name: ", mod.name ); + for(int j=0; j<mod.properties.Count; ++j) + { + VRCSDK2.VRCPlayerModProperty prop = mod.properties[j]; + myTarget.playerMods[i].properties[j] = DrawFieldForProp(prop); + } + if(GUILayout.Button ("Remove Mod")) + { + myTarget.RemoveMod(mod); + break; + } + EditorGUILayout.EndVertical(); + } + if(GUILayout.Button("Add Mods")) + { + VRCPlayerModEditorWindow.AddModCallback adcb = OnInspectorGUI; + VRCPlayerModEditorWindow.Init(myTarget, adcb); + } + } + + VRCSDK2.VRCPlayerModProperty DrawFieldForProp(VRCSDK2.VRCPlayerModProperty property) + { + if(property.type.SystemType == typeof(int)) + { + property.intValue = EditorGUILayout.IntField(property.name, property.intValue); + } + else if(property.type.SystemType == typeof(float)) + { + property.floatValue = EditorGUILayout.FloatField(property.name, property.floatValue); + } + else if(property.type.SystemType == typeof(string)) + { + property.stringValue = EditorGUILayout.TextField(property.name, property.stringValue); + } + else if(property.type.SystemType == typeof(bool)) + { + property.boolValue = EditorGUILayout.Toggle(property.name, property.boolValue); + } + else if(property.type.SystemType == typeof(GameObject)) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField( property.name ); + property.gameObjectValue = (GameObject) EditorGUILayout.ObjectField( property.gameObjectValue, typeof( GameObject ), true ); + EditorGUILayout.EndHorizontal(); + } + else if(property.type.SystemType == typeof(KeyCode)) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField( property.name ); + property.keyCodeValue = (KeyCode) EditorGUILayout.EnumPopup( property.keyCodeValue ); + EditorGUILayout.EndHorizontal(); + } + else if(property.type.SystemType == typeof(VRCSDK2.VRC_EventHandler.VrcBroadcastType)) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField( property.name ); + property.broadcastValue = (VRCSDK2.VRC_EventHandler.VrcBroadcastType) EditorGUILayout.EnumPopup( property.broadcastValue ); + EditorGUILayout.EndHorizontal(); + } + else if(property.type.SystemType == typeof(VRCSDK2.VRCPlayerModFactory.HealthOnDeathAction)) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField( property.name ); + property.onDeathActionValue = (VRCSDK2.VRCPlayerModFactory.HealthOnDeathAction) EditorGUILayout.EnumPopup( property.onDeathActionValue); + EditorGUILayout.EndHorizontal(); + } + else if(property.type.SystemType == typeof(RuntimeAnimatorController)) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField( property.name ); + property.animationController = (RuntimeAnimatorController) EditorGUILayout.ObjectField( property.animationController, typeof( RuntimeAnimatorController ), false ); + EditorGUILayout.EndHorizontal(); + } + return property; + } + } +} +#endif diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerModsEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerModsEditor.cs.meta new file mode 100644 index 00000000..d0bad2ea --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerModsEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 792e7964a56e51f4188e1221751642e9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerStationEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerStationEditor.cs new file mode 100644 index 00000000..167c2796 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerStationEditor.cs @@ -0,0 +1,46 @@ +#if VRC_SDK_VRCSDK2 + +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using UnityEditor; +using System; + +[CustomEditor(typeof(VRCSDK2.VRC_Station))] +public class VRCPlayerStationEditor : Editor +{ + VRCSDK2.VRC_Station myTarget; + + SerializedProperty onRemoteEnter; + SerializedProperty onRemoteExit; + SerializedProperty onLocalEnter; + SerializedProperty onLocalExit; + + void OnEnable() + { + if(myTarget == null) + myTarget = (VRCSDK2.VRC_Station)target; + onRemoteEnter = serializedObject.FindProperty("OnRemotePlayerEnterStation"); + onRemoteExit = serializedObject.FindProperty("OnRemotePlayerExitStation"); + onLocalEnter = serializedObject.FindProperty("OnLocalPlayerEnterStation"); + onLocalExit = serializedObject.FindProperty("OnLocalPlayerExitStation"); + } + + public override void OnInspectorGUI() + { + myTarget.PlayerMobility = (VRC.SDKBase.VRCStation.Mobility)EditorGUILayout.EnumPopup("Player Mobility", myTarget.PlayerMobility); + myTarget.canUseStationFromStation = EditorGUILayout.Toggle("Can Use Station From Station", myTarget.canUseStationFromStation); + myTarget.animatorController = (RuntimeAnimatorController)EditorGUILayout.ObjectField("Animator Controller", myTarget.animatorController, typeof(RuntimeAnimatorController), false); + myTarget.disableStationExit = EditorGUILayout.Toggle("Disable Station Exit", myTarget.disableStationExit); + myTarget.seated = EditorGUILayout.Toggle("Seated", myTarget.seated); + myTarget.stationEnterPlayerLocation = (Transform)EditorGUILayout.ObjectField("Player Enter Location", myTarget.stationEnterPlayerLocation, typeof(Transform), true); + myTarget.stationExitPlayerLocation = (Transform)EditorGUILayout.ObjectField("Player Exit Location", myTarget.stationExitPlayerLocation, typeof(Transform), true); + myTarget.controlsObject = (VRC.SDKBase.VRC_ObjectApi)EditorGUILayout.ObjectField("API Object", myTarget.controlsObject, typeof(VRC.SDKBase.VRC_ObjectApi), false); + + EditorGUILayout.PropertyField(onRemoteEnter, new GUIContent("On Remote Player Enter")); + EditorGUILayout.PropertyField(onRemoteExit, new GUIContent("On Remote Player Exit")); + EditorGUILayout.PropertyField(onLocalEnter, new GUIContent("On Local Player Enter")); + EditorGUILayout.PropertyField(onLocalExit, new GUIContent("On Local Player Exit")); + } +} +#endif diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerStationEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerStationEditor.cs.meta new file mode 100644 index 00000000..f24108b2 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCPlayerStationEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 5262a02c32e41e047bdfdfc3b63db8ff +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCSceneDescriptorEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCSceneDescriptorEditor.cs new file mode 100644 index 00000000..616d8a8b --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCSceneDescriptorEditor.cs @@ -0,0 +1,29 @@ +#if VRC_SDK_VRCSDK2 +using UnityEngine; +using UnityEditor; +using System.Collections; + +[CustomEditor (typeof(VRCSDK2.VRC_SceneDescriptor))] +public class VRCSceneDescriptorEditor : Editor +{ + VRCSDK2.VRC_SceneDescriptor sceneDescriptor; + VRC.Core.PipelineManager pipelineManager; + + public override void OnInspectorGUI() + { + if(sceneDescriptor == null) + sceneDescriptor = (VRCSDK2.VRC_SceneDescriptor)target; + + if(pipelineManager == null) + { + pipelineManager = sceneDescriptor.GetComponent<VRC.Core.PipelineManager>(); + if(pipelineManager == null) + sceneDescriptor.gameObject.AddComponent<VRC.Core.PipelineManager>(); + } + + DrawDefaultInspector(); + + + } +} +#endif diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCSceneDescriptorEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCSceneDescriptorEditor.cs.meta new file mode 100644 index 00000000..66325676 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRCSceneDescriptorEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e9cbc493bbbc443fb92898aa84d221ec +timeCreated: 1450463561 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_AvatarVariationsEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_AvatarVariationsEditor.cs new file mode 100644 index 00000000..c9026421 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_AvatarVariationsEditor.cs @@ -0,0 +1,130 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace VRCSDK2 +{ + //[CustomPropertyDrawer(typeof(VRC_AvatarVariations.VariationCategory))] + //public class PropertyDrawer_AvatarVariation_VariationCategory : PropertyDrawer + //{ + // public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label) + // { + // //EditorGUILayout.Label("blah"); + + // if (property == null) + // return; + + // SerializedProperty nameProperty = property.FindPropertyRelative("name"); + // //SerializedProperty mirrorProperty = property.FindPropertyRelative("mirror"); + // //SerializedProperty typeProperty = property.FindPropertyRelative("type"); + // //SerializedProperty valueProperty = null; + // //switch (typeProperty.enumValueIndex) + // //{ + // // case (int)VRC_DataStorage.VrcDataType.Bool: + // // valueProperty = property.FindPropertyRelative("valueBool"); + // // break; + // // case (int)VRC_DataStorage.VrcDataType.Float: + // // valueProperty = property.FindPropertyRelative("valueFloat"); + // // break; + // // case (int)VRC_DataStorage.VrcDataType.Int: + // // valueProperty = property.FindPropertyRelative("valueInt"); + // // break; + // // case (int)VRC_DataStorage.VrcDataType.String: + // // valueProperty = property.FindPropertyRelative("valueString"); + // // break; + // // case (int)VRC_DataStorage.VrcDataType.SerializeObject: + // // valueProperty = property.FindPropertyRelative("serializeComponent"); + // // break; + // // case (int)VRC_DataStorage.VrcDataType.None: + // // case (int)VRC_DataStorage.VrcDataType.SerializeBytes: + // // break; + // //} + + // EditorGUI.BeginProperty(rect, label, property); + + // int baseWidth = (int)(rect.width / 4); + // Rect nameRect = new Rect(rect.x, rect.y, baseWidth, rect.height); + // //Rect mirrorRect = new Rect(rect.x + baseWidth, rect.y, baseWidth, rect.height); + // //Rect typeRect = new Rect(rect.x + baseWidth * 2, rect.y, baseWidth, rect.height); + // //Rect valueRect = new Rect(rect.x + baseWidth * 3, rect.y, baseWidth, rect.height); + // //Rect typeValueRect = new Rect(rect.x + baseWidth * 2, rect.y, baseWidth * 2, rect.height); + + // EditorGUI.PropertyField(nameRect, nameProperty, GUIContent.none); + // //EditorGUI.PropertyField(mirrorRect, mirrorProperty, GUIContent.none); + + // //switch (mirrorProperty.enumValueIndex) + // //{ + // // case (int)VRC_DataStorage.VrcDataMirror.None: + // // if (valueProperty == null) + // // VRC_EditorTools.FilteredEnumPopup<VRC_DataStorage.VrcDataType>(typeValueRect, typeProperty, t => true); + // // else + // // { + // // VRC_EditorTools.FilteredEnumPopup<VRC_DataStorage.VrcDataType>(typeRect, typeProperty, t => true); + // // EditorGUI.PropertyField(valueRect, valueProperty, GUIContent.none); + // // } + // // break; + // // case (int)VRC_DataStorage.VrcDataMirror.SerializeComponent: + // // typeProperty.enumValueIndex = (int)VRC_DataStorage.VrcDataType.SerializeObject; + // // EditorGUI.PropertyField(typeValueRect, valueProperty, GUIContent.none); + // // break; + // // default: + // // VRC_EditorTools.FilteredEnumPopup<VRC_DataStorage.VrcDataType>(typeValueRect, typeProperty, t => true); + // // break; + // //} + + // EditorGUI.EndProperty(); + // } + //} + + //[CustomEditor(typeof(VRC_AvatarVariations))] + //public class VRC_AvatarVariationsEditor : Editor + //{ + // SerializedProperty categories; + + // void OnEnable() + // { + // categories = serializedObject.FindProperty("categories"); + // } + + // public override void OnInspectorGUI() + // { + // //serializedObject.Update(); + // // EditorGUILayout.PropertyField(categories); + // //serializedObject.ApplyModifiedProperties(); + + + + // //if (target == null) + // // return; + + // ////var prop = serializedObject.FindProperty("root"); + // ////EditorGUILayout.PropertyField(prop, new GUIContent("Show Help")); + // //VRCSDK2.VRC_AvatarVariations variations = target as VRCSDK2.VRC_AvatarVariations; + // //if (variations.categories == null) + // // variations.categories = new VRC_AvatarVariations.VariationCategory[0]; + + // //foreach ( var vc in variations.categories ) + // //{ + // // vc.name = EditorGUILayout.TextField("Variation Name", vc.name); + // //// SerializedProperty triggers = triggersProperty.Copy(); + // //// int triggersLength = triggers.arraySize; + + // //// List<int> to_remove = new List<int>(); + // //// for (int idx = 0; idx < triggersLength; ++idx) + // //// { + // //// SerializedProperty triggerProperty = triggers.GetArrayElementAtIndex(idx); + // //// } + + // //// EditorGUILayout.LabelField(""); + // ////// helpProperty = serializedObject.FindProperty("ShowHelp"); + // ////// EditorGUILayout.PropertyField(helpProperty, new GUIContent("Show Help")); + // //} + + // ////EditorGUILayout. + + // DrawDefaultInspector(); + // } + //} + +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_AvatarVariationsEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_AvatarVariationsEditor.cs.meta new file mode 100644 index 00000000..b4f3a9ff --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_AvatarVariationsEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: eeda995d0ceac6443a54716996eab52e +timeCreated: 1511373338 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_DataStorageEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_DataStorageEditor.cs new file mode 100644 index 00000000..bdc19188 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_DataStorageEditor.cs @@ -0,0 +1,91 @@ +#if VRC_SDK_VRCSDK2 && UNITY_EDITOR +using UnityEditor; +using UnityEngine; +using VRC.SDKBase; + +namespace VRCSDK2 +{ + [CustomPropertyDrawer(typeof(VRCSDK2.VRC_DataStorage.VrcDataElement))] + public class CustomDataElementDrawer : PropertyDrawer + { + public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label) + { + if (property == null) + return; + + SerializedProperty nameProperty = property.FindPropertyRelative("name"); + SerializedProperty mirrorProperty = property.FindPropertyRelative("mirror"); + SerializedProperty typeProperty = property.FindPropertyRelative("type"); + SerializedProperty valueProperty = null; + switch (typeProperty.enumValueIndex) + { + case (int)VRCSDK2.VRC_DataStorage.VrcDataType.Bool: + valueProperty = property.FindPropertyRelative("valueBool"); + break; + case (int)VRCSDK2.VRC_DataStorage.VrcDataType.Float: + valueProperty = property.FindPropertyRelative("valueFloat"); + break; + case (int)VRCSDK2.VRC_DataStorage.VrcDataType.Int: + valueProperty = property.FindPropertyRelative("valueInt"); + break; + case (int)VRCSDK2.VRC_DataStorage.VrcDataType.String: + valueProperty = property.FindPropertyRelative("valueString"); + break; + case (int)VRCSDK2.VRC_DataStorage.VrcDataType.SerializeObject: + valueProperty = property.FindPropertyRelative("serializeComponent"); + break; + case (int)VRCSDK2.VRC_DataStorage.VrcDataType.None: + case (int)VRCSDK2.VRC_DataStorage.VrcDataType.SerializeBytes: + break; + } + + EditorGUI.BeginProperty(rect, label, property); + + int baseWidth = (int)(rect.width / 4); + Rect nameRect = new Rect(rect.x, rect.y, baseWidth, rect.height); + Rect mirrorRect = new Rect(rect.x + baseWidth, rect.y, baseWidth, rect.height); + Rect typeRect = new Rect(rect.x + baseWidth * 2, rect.y, baseWidth, rect.height); + Rect valueRect = new Rect(rect.x + baseWidth * 3, rect.y, baseWidth, rect.height); + Rect typeValueRect = new Rect(rect.x + baseWidth * 2, rect.y, baseWidth * 2, rect.height); + + EditorGUI.PropertyField(nameRect, nameProperty, GUIContent.none); + EditorGUI.PropertyField(mirrorRect, mirrorProperty, GUIContent.none); + + switch (mirrorProperty.enumValueIndex) + { + case (int)VRCSDK2.VRC_DataStorage.VrcDataMirror.None: + if (valueProperty == null) + VRC_EditorTools.FilteredEnumPopup<VRCSDK2.VRC_DataStorage.VrcDataType>(typeValueRect, typeProperty, t => true); + else + { + VRC_EditorTools.FilteredEnumPopup<VRCSDK2.VRC_DataStorage.VrcDataType>(typeRect, typeProperty, t => true); + EditorGUI.PropertyField(valueRect, valueProperty, GUIContent.none); + } + break; + case (int)VRCSDK2.VRC_DataStorage.VrcDataMirror.SerializeComponent: + typeProperty.enumValueIndex = (int)VRCSDK2.VRC_DataStorage.VrcDataType.SerializeObject; + EditorGUI.PropertyField(typeValueRect, valueProperty, GUIContent.none); + break; + default: + VRC_EditorTools.FilteredEnumPopup<VRCSDK2.VRC_DataStorage.VrcDataType>(typeValueRect, typeProperty, t => true); + break; + } + + EditorGUI.EndProperty(); + } + } + + [CustomEditor(typeof(VRCSDK2.VRC_DataStorage)), CanEditMultipleObjects] + public class VRC_DataStorageEditor : UnityEditor.Editor + { + public override void OnInspectorGUI() + { + VRCSDK2.VRC_ObjectSync os = ((VRCSDK2.VRC_DataStorage)target).GetComponent<VRCSDK2.VRC_ObjectSync>(); + if (os != null && os.SynchronizePhysics) + EditorGUILayout.HelpBox("Consider either removing the VRC_ObjectSync or disabling SynchronizePhysics.", MessageType.Warning); + + DrawDefaultInspector(); + } + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_DataStorageEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_DataStorageEditor.cs.meta new file mode 100644 index 00000000..a46a6e7b --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_DataStorageEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0ac7998a36f085844847acbc046d4e27 +timeCreated: 1478191469 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_DestructibleStandardEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_DestructibleStandardEditor.cs new file mode 100644 index 00000000..5eaf7be0 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_DestructibleStandardEditor.cs @@ -0,0 +1,57 @@ +using UnityEngine; +using UnityEditor; +using VRC_DestructibleStandard = VRC.SDKBase.VRC_DestructibleStandard; +using VRC.SDKBase; + +[CustomEditor(typeof(VRC_DestructibleStandard))] +[CanEditMultipleObjects] +public class VRC_DestructibleStandardEditor : Editor +{ + VRC_DestructibleStandard ds; + + SerializedProperty maxHealth; + SerializedProperty currentHealth; + SerializedProperty healable; + SerializedProperty onDamagedTrigger; + SerializedProperty onDestroyedTrigger; + SerializedProperty onHealedTrigger; + SerializedProperty onFullHealedTrigger; + + void OnEnable() + { + maxHealth = serializedObject.FindProperty("maxHealth"); + currentHealth = serializedObject.FindProperty("currentHealth"); + healable = serializedObject.FindProperty("healable"); + onDamagedTrigger = serializedObject.FindProperty("onDamagedTrigger"); + onDestroyedTrigger = serializedObject.FindProperty("onDestructedTrigger"); + onHealedTrigger = serializedObject.FindProperty("onHealedTrigger"); + onFullHealedTrigger = serializedObject.FindProperty("onFullHealedTrigger"); + } + + public override void OnInspectorGUI() + { + ds = (VRC_DestructibleStandard)target; + + // Update the serializedProperty - always do this in the beginning of OnInspectorGUI. + serializedObject.Update (); + + EditorGUILayout.PropertyField(maxHealth, new GUIContent("Max Health")); + EditorGUILayout.PropertyField(currentHealth, new GUIContent("Current Health")); + EditorGUILayout.PropertyField(healable, new GUIContent("Is Healable")); + + EditorGUILayout.PropertyField(onDamagedTrigger, new GUIContent("On Damaged Trigger")); + VRC_EditorTools.DrawTriggerActionCallback("On Damaged Action", ds.onDamagedTrigger, ds.onDamagedEvent); + + EditorGUILayout.PropertyField(onDestroyedTrigger, new GUIContent("On Destructed Trigger")); + VRC_EditorTools.DrawTriggerActionCallback("On Destructed Action", ds.onDestructedTrigger, ds.onDestructedEvent); + + EditorGUILayout.PropertyField(onHealedTrigger, new GUIContent("On Healed Trigger")); + VRC_EditorTools.DrawTriggerActionCallback("On Healed Action", ds.onHealedTrigger, ds.onHealedEvent); + + EditorGUILayout.PropertyField(onFullHealedTrigger, new GUIContent("On Full Healed Trigger")); + VRC_EditorTools.DrawTriggerActionCallback("On Full Healed Action", ds.onFullHealedTrigger, ds.onFullHealedEvent); + + // Apply changes to the serializedProperty - always do this in the end of OnInspectorGUI. + serializedObject.ApplyModifiedProperties (); + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_DestructibleStandardEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_DestructibleStandardEditor.cs.meta new file mode 100644 index 00000000..34d65d25 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_DestructibleStandardEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3b63b118c0591b548ba1797e6be4292e +timeCreated: 1477161996 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_ObjectSyncEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_ObjectSyncEditor.cs new file mode 100644 index 00000000..13686eae --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_ObjectSyncEditor.cs @@ -0,0 +1,19 @@ +#if VRC_SDK_VRCSDK2 +using System.Collections; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +[CustomEditor(typeof(VRCSDK2.VRC_ObjectSync))] +public class VRC_ObjectSyncEditor : Editor { + public override void OnInspectorGUI() + { + VRCSDK2.VRC_ObjectSync c = ((VRCSDK2.VRC_ObjectSync)target); + if ((c.gameObject.GetComponent<Animator>() != null || c.gameObject.GetComponent<Animation>() != null) && c.SynchronizePhysics) + EditorGUILayout.HelpBox("If the Animator or Animation moves the root position of this object then it will conflict with physics synchronization.", MessageType.Warning); + if (c.GetComponent<VRCSDK2.VRC_DataStorage>() != null && c.SynchronizePhysics) + EditorGUILayout.HelpBox("Consider either removing the VRC_DataStorage or disabling SynchronizePhysics.", MessageType.Warning); + DrawDefaultInspector(); + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_ObjectSyncEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_ObjectSyncEditor.cs.meta new file mode 100644 index 00000000..7cf90f30 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_ObjectSyncEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e19a7147a2386554a8e4d6e414f190a2 +timeCreated: 1504908295 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_PickupEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_PickupEditor.cs new file mode 100644 index 00000000..947dba7d --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_PickupEditor.cs @@ -0,0 +1,70 @@ +#if VRC_SDK_VRCSDK2 && UNITY_EDITOR +using UnityEditor; +using UnityEngine; + +namespace VRCSDK2 +{ + [CustomEditor(typeof(VRCSDK2.VRC_Pickup))] + public class VRC_PickupEditor : UnityEditor.Editor + { + private void InspectorField(string propertyName, string humanName) + { + SerializedProperty propertyField = serializedObject.FindProperty(propertyName); + EditorGUILayout.PropertyField(propertyField, new GUIContent(humanName), true); + } + + private SerializedProperty momentumTransferMethodProperty; + private SerializedProperty disallowTheftProperty; + private SerializedProperty exactGunProperty; + private SerializedProperty exactGripProperty; + private SerializedProperty allowManipulationWhenEquippedProperty; + private SerializedProperty orientationProperty; + private SerializedProperty autoHoldProperty; + private SerializedProperty interactionTextProperty; + private SerializedProperty useTextProperty; + private SerializedProperty throwVelocityBoostMinSpeedProperty; + private SerializedProperty throwVelocityBoostScaleProperty; + private SerializedProperty pickupableProperty; + private SerializedProperty proximityProperty; + + public override void OnInspectorGUI() + { + momentumTransferMethodProperty = serializedObject.FindProperty("MomentumTransferMethod"); + disallowTheftProperty = serializedObject.FindProperty("DisallowTheft"); + exactGunProperty = serializedObject.FindProperty("ExactGun"); + exactGripProperty = serializedObject.FindProperty("ExactGrip"); + allowManipulationWhenEquippedProperty = serializedObject.FindProperty("allowManipulationWhenEquipped"); + orientationProperty = serializedObject.FindProperty("orientation"); + autoHoldProperty = serializedObject.FindProperty("AutoHold"); + interactionTextProperty = serializedObject.FindProperty("InteractionText"); + useTextProperty = serializedObject.FindProperty("UseText"); + throwVelocityBoostMinSpeedProperty = serializedObject.FindProperty("ThrowVelocityBoostMinSpeed"); + throwVelocityBoostScaleProperty = serializedObject.FindProperty("ThrowVelocityBoostScale"); + pickupableProperty = serializedObject.FindProperty("pickupable"); + proximityProperty = serializedObject.FindProperty("proximity"); + + EditorGUILayout.BeginVertical(GUILayout.MaxWidth(EditorGUIUtility.currentViewWidth - 30)); + + EditorGUILayout.PropertyField(momentumTransferMethodProperty, new GUIContent("Momentum Transfer Method")); + EditorGUILayout.PropertyField(disallowTheftProperty, new GUIContent("Disallow Theft")); + EditorGUILayout.PropertyField(exactGunProperty, new GUIContent("Exact Gun")); + EditorGUILayout.PropertyField(exactGripProperty, new GUIContent("Exact Grip")); + EditorGUILayout.PropertyField(allowManipulationWhenEquippedProperty, new GUIContent("Allow Manipulation When Equipped")); + EditorGUILayout.PropertyField(orientationProperty, new GUIContent("Orientation")); + EditorGUILayout.PropertyField(autoHoldProperty, new GUIContent("AutoHold", "If the pickup is supposed to be aligned to the hand (i.e. orientation field is set to Gun or Grip), auto-detect means that it will be Equipped(not dropped when they release trigger), otherwise just hold as a normal pickup.")); + EditorGUILayout.PropertyField(interactionTextProperty, new GUIContent("Interaction Text","Text displayed when user hovers over the pickup.")); + if (autoHoldProperty.enumValueIndex != (int)VRCSDK2.VRC_Pickup.AutoHoldMode.No) + EditorGUILayout.PropertyField(useTextProperty, new GUIContent("Use Text", "Text to display describing action for clicking button, when this pickup is already being held.")); + EditorGUILayout.PropertyField(throwVelocityBoostMinSpeedProperty, new GUIContent("Throw Velocity Boost Min Speed")); + EditorGUILayout.PropertyField(throwVelocityBoostScaleProperty, new GUIContent("Throw Velocity Boost Scale")); + EditorGUILayout.PropertyField(pickupableProperty, new GUIContent("Pickupable")); + EditorGUILayout.PropertyField(proximityProperty, new GUIContent("Proximity")); + + EditorGUILayout.EndVertical(); + + serializedObject.ApplyModifiedProperties(); + } + + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_PickupEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_PickupEditor.cs.meta new file mode 100644 index 00000000..02042125 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_PickupEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4aff4e5c0d600c845b29d7b8b7965d68 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_PlayerAudioOverrideEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_PlayerAudioOverrideEditor.cs new file mode 100644 index 00000000..e2138127 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_PlayerAudioOverrideEditor.cs @@ -0,0 +1,106 @@ +#if VRC_SDK_VRCSDK2 +using UnityEngine; +using UnityEngine.UI; +using UnityEditor; +using System; + +namespace VRCSDK2 +{ + [CustomEditor(typeof(VRCSDK2.VRC_PlayerAudioOverride))] + public class VRC_PlayerAudioOverrideEditor : UnityEditor.Editor + { + private bool voShow = true; + private bool voAdv = false; + private bool avShow = true; + private bool avAdv = false; + private SerializedProperty prioProperty; + private SerializedProperty globalProperty; + private SerializedProperty regionProperty; + private SerializedProperty voGainProperty; + private SerializedProperty voNearProperty; + private SerializedProperty voFarProperty; + private SerializedProperty voRadiusProperty; + private SerializedProperty voDisableLpProperty; + private SerializedProperty avGainProperty; + private SerializedProperty avNearProperty; + private SerializedProperty avFarProperty; + private SerializedProperty avRadiusProperty; + private SerializedProperty avForceSpatialProperty; + private SerializedProperty avAllowCustomProperty; + + public override void OnInspectorGUI() + { + globalProperty = serializedObject.FindProperty("global"); + regionProperty = serializedObject.FindProperty("region"); + prioProperty = serializedObject.FindProperty("regionPriority"); + + voGainProperty = serializedObject.FindProperty("VoiceGain"); + voNearProperty = serializedObject.FindProperty("VoiceNear"); + voFarProperty = serializedObject.FindProperty("VoiceFar"); + voRadiusProperty = serializedObject.FindProperty("VoiceVolumetricRadius"); + voDisableLpProperty = serializedObject.FindProperty("VoiceDisableLowpass"); + + avGainProperty = serializedObject.FindProperty("AvatarGainLimit"); + avNearProperty = serializedObject.FindProperty("AvatarNearLimit"); + avFarProperty = serializedObject.FindProperty("AvatarFarLimit"); + avRadiusProperty = serializedObject.FindProperty("AvatarVolumetricRadiusLimit"); + avForceSpatialProperty = serializedObject.FindProperty("AvatarForceSpatial"); + avAllowCustomProperty = serializedObject.FindProperty("AvatarAllowCustomCurve"); + + serializedObject.Update(); + + EditorGUILayout.BeginVertical(); + + var ovr = serializedObject.targetObject as VRCSDK2.VRC_PlayerAudioOverride; + + EditorGUILayout.PropertyField(globalProperty, new GUIContent("Global")); + if (!ovr.global) + { + EditorGUILayout.PropertyField(regionProperty, new GUIContent("Region")); + EditorGUILayout.PropertyField(prioProperty, new GUIContent("Priority")); + } + + voShow = EditorGUILayout.Foldout(voShow, "Voice Settings"); + + if (voShow) + { + EditorGUILayout.PropertyField(voGainProperty, new GUIContent("Gain")); + EditorGUILayout.PropertyField(voFarProperty, new GUIContent("Far")); + + EditorGUI.indentLevel++; + voAdv = EditorGUILayout.Foldout(voAdv, "Advanced Options"); + if (voAdv) + { + EditorGUILayout.PropertyField(voNearProperty, new GUIContent("Near")); + EditorGUILayout.PropertyField(voRadiusProperty, new GUIContent("Volumetric Radius")); + EditorGUILayout.PropertyField(voDisableLpProperty, new GUIContent("Disable Lowpass Filter")); + } + EditorGUI.indentLevel--; + } + + avShow = EditorGUILayout.Foldout(avShow, "Avatar Audio Limits"); + + if (avShow) + { + EditorGUILayout.PropertyField(avGainProperty, new GUIContent("Gain Limit")); + EditorGUILayout.PropertyField(avFarProperty, new GUIContent("Far Limit")); + + EditorGUI.indentLevel++; + avAdv = EditorGUILayout.Foldout(avAdv, "Advanced Options"); + if (avAdv) + { + EditorGUILayout.PropertyField(avNearProperty, new GUIContent("Near Limit")); + EditorGUILayout.PropertyField(avRadiusProperty, new GUIContent("Volumetric Radius Limit")); + EditorGUILayout.PropertyField(avForceSpatialProperty, new GUIContent("Force Spatial")); + EditorGUILayout.PropertyField(avAllowCustomProperty, new GUIContent("Allow Custom Curve")); + } + EditorGUI.indentLevel--; + } + + EditorGUILayout.EndVertical(); + + serializedObject.ApplyModifiedProperties(); + } + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_PlayerAudioOverrideEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_PlayerAudioOverrideEditor.cs.meta new file mode 100644 index 00000000..d7bfd85c --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_PlayerAudioOverrideEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5c545625e0bf93045ac1c5864141c5c1 +timeCreated: 1474315179 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SpatialAudioSourceEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SpatialAudioSourceEditor.cs new file mode 100644 index 00000000..c7145db2 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SpatialAudioSourceEditor.cs @@ -0,0 +1,58 @@ +#if VRC_SDK_VRCSDK2 && UNITY_EDITOR + +using UnityEngine; +using UnityEngine.UI; +using UnityEditor; +using System; + +namespace VRCSDK2 +{ + [CustomEditor(typeof(VRCSDK2.VRC_SpatialAudioSource))] + public class VRC_SpatialAudioSourceEditor : UnityEditor.Editor + { + private bool showAdvancedOptions = false; + private SerializedProperty gainProperty; + private SerializedProperty nearProperty; + private SerializedProperty farProperty; + private SerializedProperty volRadiusProperty; + private SerializedProperty enableSpatialProperty; + private SerializedProperty useCurveProperty; + + public override void OnInspectorGUI() + { + gainProperty = serializedObject.FindProperty("Gain"); + nearProperty = serializedObject.FindProperty("Near"); + farProperty = serializedObject.FindProperty("Far"); + volRadiusProperty = serializedObject.FindProperty("VolumetricRadius"); + enableSpatialProperty = serializedObject.FindProperty("EnableSpatialization"); + useCurveProperty = serializedObject.FindProperty("UseAudioSourceVolumeCurve"); + + serializedObject.Update(); + + VRCSDK2.VRC_SpatialAudioSource target = serializedObject.targetObject as VRCSDK2.VRC_SpatialAudioSource; + AudioSource source = target.GetComponent<AudioSource>(); + + EditorGUILayout.BeginVertical(); + + EditorGUILayout.PropertyField(gainProperty, new GUIContent("Gain")); + EditorGUILayout.PropertyField(farProperty, new GUIContent("Far")); + showAdvancedOptions = EditorGUILayout.Foldout(showAdvancedOptions, "Advanced Options"); + bool enableSp = enableSpatialProperty.boolValue; + if (showAdvancedOptions) + { + EditorGUILayout.PropertyField(nearProperty, new GUIContent("Near")); + EditorGUILayout.PropertyField(volRadiusProperty, new GUIContent("Volumetric Radius")); + EditorGUILayout.PropertyField(enableSpatialProperty, new GUIContent("Enable Spatialization")); + if (enableSp) + EditorGUILayout.PropertyField(useCurveProperty, new GUIContent("Use AudioSource Volume Curve")); + } + + EditorGUILayout.EndVertical(); + + if (source != null) + source.spatialize = enableSp; + serializedObject.ApplyModifiedProperties(); + } + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SpatialAudioSourceEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SpatialAudioSourceEditor.cs.meta new file mode 100644 index 00000000..3f7ca463 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SpatialAudioSourceEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0d2d4cba733f5eb4ba170368e67710d2 +timeCreated: 1474315179 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SyncVideoPlayerEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SyncVideoPlayerEditor.cs new file mode 100644 index 00000000..5498e5da --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SyncVideoPlayerEditor.cs @@ -0,0 +1,105 @@ +#if VRC_SDK_VRCSDK2 + +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using UnityEditorInternal; +using VRC.SDKBase; + +[CustomPropertyDrawer(typeof(VRCSDK2.VRC_SyncVideoPlayer.VideoEntry))] +public class CustomVideoEntryDrawer : PropertyDrawer +{ + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + SerializedProperty source = property.FindPropertyRelative("Source"); + SerializedProperty ratio = property.FindPropertyRelative("AspectRatio"); + SerializedProperty speed = property.FindPropertyRelative("PlaybackSpeed"); + SerializedProperty clip = property.FindPropertyRelative("VideoClip"); + SerializedProperty url = property.FindPropertyRelative("URL"); + + return EditorGUI.GetPropertyHeight(source, new GUIContent("Source"), true) + EditorGUIUtility.standardVerticalSpacing + + EditorGUI.GetPropertyHeight(ratio, new GUIContent("Aspect Ratio"), true) + EditorGUIUtility.standardVerticalSpacing + + EditorGUI.GetPropertyHeight(speed, new GUIContent("Playback Speed"), true) + EditorGUIUtility.standardVerticalSpacing + + Mathf.Max(EditorGUI.GetPropertyHeight(clip, new GUIContent("VideoClip"), true), EditorGUI.GetPropertyHeight(url, new GUIContent("URL"), true)) + EditorGUIUtility.standardVerticalSpacing; + } + + public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label) + { + SerializedProperty source = property.FindPropertyRelative("Source"); + SerializedProperty ratio = property.FindPropertyRelative("AspectRatio"); + SerializedProperty speed = property.FindPropertyRelative("PlaybackSpeed"); + SerializedProperty clip = property.FindPropertyRelative("VideoClip"); + SerializedProperty url = property.FindPropertyRelative("URL"); + + EditorGUI.BeginProperty(rect, label, property); + float x = rect.x; + float y = rect.y; + float w = rect.width; + float h = EditorGUI.GetPropertyHeight(source, new GUIContent("Source"), true) + EditorGUIUtility.standardVerticalSpacing; + VRC_EditorTools.FilteredEnumPopup<UnityEngine.Video.VideoSource>(new Rect(x, y, w, h), source, (e) => e == UnityEngine.Video.VideoSource.Url); + y += h; + + if (source.enumValueIndex == (int)UnityEngine.Video.VideoSource.Url) + { + h = EditorGUI.GetPropertyHeight(url, new GUIContent("URL"), true) + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(new Rect(x, y, w, h), url); + y += h; + } + else + { + h = EditorGUI.GetPropertyHeight(clip, new GUIContent("VideoClip"), true) + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(new Rect(x, y, w, h), clip); + y += h; + } + + h = EditorGUI.GetPropertyHeight(ratio, new GUIContent("AspectRatio"), true) + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(new Rect(x, y, w, h), ratio); + y += h; + + h = EditorGUI.GetPropertyHeight(ratio, new GUIContent("Playback Speed"), true) + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(new Rect(x, y, w, h), speed); + if (speed.floatValue == 0f) + speed.floatValue = 1f; + y += h; + + EditorGUI.EndProperty(); + } +} + +[CustomEditor(typeof(VRCSDK2.VRC_SyncVideoPlayer))] +public class SyncVideoPlayerEditor : Editor +{ + ReorderableList sourceList; + + public override void OnInspectorGUI() + { + SerializedProperty searchRoot = serializedObject.FindProperty("VideoSearchRoot"); + EditorGUILayout.PropertyField(searchRoot); + SerializedProperty maxQual = serializedObject.FindProperty("MaxStreamQuality"); + EditorGUILayout.PropertyField(maxQual); + + EditorGUILayout.Space(); + + sourceList.DoLayoutList(); + + serializedObject.ApplyModifiedProperties(); + } + + private void OnEnable() + { + SerializedProperty videos = serializedObject.FindProperty("Videos"); + sourceList = new ReorderableList(serializedObject, videos); + sourceList.drawElementCallback += (Rect rect, int index, bool active, bool focused) => + { + EditorGUI.PropertyField(rect, serializedObject.FindProperty("Videos").GetArrayElementAtIndex(index)); + }; + sourceList.elementHeightCallback += (int index) => + { + SerializedProperty element = serializedObject.FindProperty("Videos").GetArrayElementAtIndex(index); + return EditorGUI.GetPropertyHeight(element); + }; + sourceList.drawHeaderCallback = (Rect rect) => EditorGUI.LabelField(rect, "Videos"); + } +} +#endif diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SyncVideoPlayerEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SyncVideoPlayerEditor.cs.meta new file mode 100644 index 00000000..616cee0f --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SyncVideoPlayerEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ae0e74693b7899f47bd98864f94b9311 +timeCreated: 1499468412 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SyncVideoStreamEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SyncVideoStreamEditor.cs new file mode 100644 index 00000000..198f7ffa --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SyncVideoStreamEditor.cs @@ -0,0 +1,117 @@ +#if VRC_SDK_VRCSDK2 + +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using UnityEditorInternal; +using VRC.SDKBase; + +[CustomPropertyDrawer(typeof(VRCSDK2.VRC_SyncVideoStream.VideoEntry))] +public class CustomVideoStreamEntryDrawer : PropertyDrawer +{ + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + SerializedProperty source = property.FindPropertyRelative("Source"); + SerializedProperty speed = property.FindPropertyRelative("PlaybackSpeed"); + SerializedProperty clip = property.FindPropertyRelative("VideoClip"); + SerializedProperty url = property.FindPropertyRelative("URL"); + SerializedProperty live = property.FindPropertyRelative("SyncType"); + SerializedProperty sync = property.FindPropertyRelative("SyncMinutes"); + + return EditorGUI.GetPropertyHeight(source, new GUIContent("Source"), true) + EditorGUIUtility.standardVerticalSpacing + + EditorGUI.GetPropertyHeight(speed, new GUIContent("Playback Speed"), true) + EditorGUIUtility.standardVerticalSpacing + + Mathf.Max(EditorGUI.GetPropertyHeight(clip, new GUIContent("VideoClip"), true), EditorGUI.GetPropertyHeight(url, new GUIContent("URL"), true)) + EditorGUIUtility.standardVerticalSpacing + + EditorGUI.GetPropertyHeight(live, new GUIContent("SyncType"), true) + EditorGUIUtility.standardVerticalSpacing + + EditorGUI.GetPropertyHeight(sync, new GUIContent("SyncMinutes"), true) + EditorGUIUtility.standardVerticalSpacing; + } + + public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label) + { + SerializedProperty source = property.FindPropertyRelative("Source"); + SerializedProperty speed = property.FindPropertyRelative("PlaybackSpeed"); + SerializedProperty clip = property.FindPropertyRelative("VideoClip"); + SerializedProperty url = property.FindPropertyRelative("URL"); + SerializedProperty live = property.FindPropertyRelative("SyncType"); + SerializedProperty sync = property.FindPropertyRelative("SyncMinutes"); + + EditorGUI.BeginProperty(rect, label, property); + float x = rect.x; + float y = rect.y; + float w = rect.width; + float h = EditorGUI.GetPropertyHeight(source, new GUIContent("Source"), true) + EditorGUIUtility.standardVerticalSpacing; + VRC_EditorTools.FilteredEnumPopup<UnityEngine.Video.VideoSource>(new Rect(x, y, w, h), source, (e) => e == UnityEngine.Video.VideoSource.Url); + y += h; + + if (source.enumValueIndex == (int)UnityEngine.Video.VideoSource.Url) + { + h = EditorGUI.GetPropertyHeight(url, new GUIContent("URL"), true) + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(new Rect(x, y, w, h), url); + y += h; + } + else + { + h = EditorGUI.GetPropertyHeight(clip, new GUIContent("VideoClip"), true) + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(new Rect(x, y, w, h), clip); + y += h; + } + + h = EditorGUI.GetPropertyHeight(speed, new GUIContent("Playback Speed"), true) + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(new Rect(x, y, w, h), speed); + if (speed.floatValue == 0f) + speed.floatValue = 1f; + y += h; + + h = EditorGUI.GetPropertyHeight(live, new GUIContent("SyncType"), true) + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(new Rect(x, y, w, h), live); + y += h; + + h = EditorGUI.GetPropertyHeight(sync, new GUIContent("SyncMinutes"), true) + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(new Rect(x, y, w, h), sync); + if (sync.floatValue < 1f) + sync.floatValue = 0; + y += h; + + EditorGUI.EndProperty(); + } +} + +[CustomEditor(typeof(VRCSDK2.VRC_SyncVideoStream))] +public class SyncVideoStreamEditor : Editor +{ + ReorderableList sourceList; + + public override void OnInspectorGUI() + { + SerializedProperty searchRoot = serializedObject.FindProperty("VideoSearchRoot"); + EditorGUILayout.PropertyField(searchRoot); + SerializedProperty maxQual = serializedObject.FindProperty("MaxStreamQuality"); + EditorGUILayout.PropertyField(maxQual); + SerializedProperty autoStart = serializedObject.FindProperty("AutoStart"); + EditorGUILayout.PropertyField(autoStart); + + EditorGUILayout.Space(); + + sourceList.DoLayoutList(); + + serializedObject.ApplyModifiedProperties(); + } + + private void OnEnable() + { + SerializedProperty videos = serializedObject.FindProperty("Videos"); + sourceList = new ReorderableList(serializedObject, videos); + sourceList.drawElementCallback += (Rect rect, int index, bool active, bool focused) => + { + EditorGUI.PropertyField(rect, serializedObject.FindProperty("Videos").GetArrayElementAtIndex(index)); + }; + sourceList.elementHeightCallback += (int index) => + { + SerializedProperty element = serializedObject.FindProperty("Videos").GetArrayElementAtIndex(index); + return EditorGUI.GetPropertyHeight(element); + }; + sourceList.drawHeaderCallback = (Rect rect) => EditorGUI.LabelField(rect, "Videos"); + } +} + +#endif diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SyncVideoStreamEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SyncVideoStreamEditor.cs.meta new file mode 100644 index 00000000..ad3b7ed2 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_SyncVideoStreamEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3f9dccfed0b072f49a307b3f20a7e768 +timeCreated: 1528745185 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_TriggerEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_TriggerEditor.cs new file mode 100644 index 00000000..f137e724 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_TriggerEditor.cs @@ -0,0 +1,1524 @@ +#if VRC_SDK_VRCSDK2 && UNITY_EDITOR + +using UnityEngine; +using UnityEngine.UI; +using UnityEditor; +using UnityEditorInternal; +using System.Linq; +using System.Collections.Generic; +using System.Reflection; +using System; +using VRC.SDKBase; +using VRC.SDKBase.Editor; + +namespace VRCSDK2 +{ + [CustomPropertyDrawer(typeof(VRCSDK2.VRC_Trigger.CustomTriggerTarget))] + public class CustomTriggerTargetDrawer : PropertyDrawer + { + public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label) + { + if (Application.isPlaying) + { + EditorGUI.HelpBox(rect, "Trigger Editor disabled while application is running.", MessageType.Info); + return; + } + + if (property == null) + return; + + SerializedProperty objectProperty = property.FindPropertyRelative("TriggerObject"); + SerializedProperty nameProperty = property.FindPropertyRelative("CustomName"); + + EditorGUI.BeginProperty(rect, label, property); + + rect = EditorGUI.PrefixLabel(rect, GUIUtility.GetControlID(FocusType.Passive), label); + Rect objectRect = new Rect(rect.x, rect.y, rect.width / 2 - 5, rect.height); + Rect nameRect = new Rect(rect.x + rect.width / 2, rect.y, rect.width / 2, rect.height); + + VRCSDK2.VRC_Trigger current = null; + if (objectProperty.objectReferenceValue != null) + current = (objectProperty.objectReferenceValue as GameObject).GetComponent<VRCSDK2.VRC_Trigger>(); + current = EditorGUI.ObjectField(objectRect, current, typeof(VRCSDK2.VRC_Trigger), true) as VRCSDK2.VRC_Trigger; + objectProperty.objectReferenceValue = current == null ? null : current.gameObject; + + VRC_EditorTools.CustomTriggerPopup(nameRect, objectProperty, nameProperty); + + EditorGUI.EndProperty(); + } + } + + [CustomEditor(typeof(VRCSDK2.VRC_Trigger)), CanEditMultipleObjects] + public class VRC_TriggerEditor : UnityEditor.Editor + { + private List<VRCSDK2.VRC_Trigger.TriggerType> ActiveTypes + { + get + { + List<VRCSDK2.VRC_Trigger.TriggerType> activeTypes = new List<VRCSDK2.VRC_Trigger.TriggerType>(); + + SerializedProperty triggers = triggersProperty.Copy(); + int triggersLength = triggers.arraySize; + + for (int idx = 0; idx < triggersLength; ++idx) + { + VRCSDK2.VRC_Trigger.TriggerType triggerType = (VRCSDK2.VRC_Trigger.TriggerType)triggers.GetArrayElementAtIndex(idx).FindPropertyRelative("TriggerType").intValue; + activeTypes.Add(triggerType); + } + + return activeTypes; + } + } + +#pragma warning disable CS0618 // Type or member is obsolete + private static List<VRCSDK2.VRC_Trigger.TriggerType> hiddenTriggerTypes = new List<VRCSDK2.VRC_Trigger.TriggerType> { /*VRCSDK2.VRC_Trigger.TriggerType.OnDataStorageAdd, VRCSDK2.VRC_Trigger.TriggerType.OnDataStorageRemove*/ }; + private static List<VRCSDK2.VRC_EventHandler.VrcEventType> hiddenEventTypes = new List<VRCSDK2.VRC_EventHandler.VrcEventType> { VRCSDK2.VRC_EventHandler.VrcEventType.MeshVisibility, VRCSDK2.VRC_EventHandler.VrcEventType.SendMessage, VRCSDK2.VRC_EventHandler.VrcEventType.RunConsoleCommand }; + private static List<VRCSDK2.VRC_EventHandler.VrcBroadcastType> unbufferedBroadcastTypes = new List<VRCSDK2.VRC_EventHandler.VrcBroadcastType> { VRCSDK2.VRC_EventHandler.VrcBroadcastType.AlwaysUnbuffered, VRCSDK2.VRC_EventHandler.VrcBroadcastType.MasterUnbuffered, VRCSDK2.VRC_EventHandler.VrcBroadcastType.OwnerUnbuffered, VRCSDK2.VRC_EventHandler.VrcBroadcastType.Local }; + private static List<VRCSDK2.VRC_EventHandler.VrcBroadcastType> bufferOneBroadcastTypes = new List<VRCSDK2.VRC_EventHandler.VrcBroadcastType> { VRCSDK2.VRC_EventHandler.VrcBroadcastType.AlwaysBufferOne, VRCSDK2.VRC_EventHandler.VrcBroadcastType.MasterBufferOne, VRCSDK2.VRC_EventHandler.VrcBroadcastType.OwnerBufferOne }; + private static List<VRCSDK2.VRC_EventHandler.VrcBroadcastType> hiddenBroadcastTypes = new List<VRCSDK2.VRC_EventHandler.VrcBroadcastType> { }; +#pragma warning restore CS0618 // Type or member is obsolete + + private ReorderableList[] eventLists = new ReorderableList[0]; + private ReorderableList[] relayLists = new ReorderableList[0]; + private ReorderableList[] objectLists = new ReorderableList[0]; + private bool[] visible = new bool[0]; + + private SerializedProperty triggersProperty; + private SerializedProperty proximityProperty; + private SerializedProperty interactTextProperty; + private SerializedProperty ownershipProperty; + private SerializedProperty drawLinesProperty; + + private Dictionary<string, object[]> rpcByteCache = new Dictionary<string, object[]>(); + + private VRCSDK2.VRC_Trigger.TriggerType addTriggerSelectedType = VRCSDK2.VRC_Trigger.TriggerType.Custom; + + private void OnEnable() + { + rpcByteCache.Clear(); + } + + public override void OnInspectorGUI() + { +#pragma warning disable CS0618 // Type or member is obsolete + bool showedOldWarning = false; + foreach (VRCSDK2.VRC_Trigger t in targets.Cast<VRCSDK2.VRC_Trigger>().Where(tr => tr != null)) + { + if (!showedOldWarning && (t.GetComponent<VRCSDK2.VRC_UseEvents>() != null || t.GetComponent<VRCSDK2.VRC_KeyEvents>() != null || t.GetComponent<VRCSDK2.VRC_TriggerColliderEventTrigger>() != null || t.GetComponent<VRCSDK2.VRC_TimedEvents>() != null)) + { + EditorGUILayout.HelpBox("Do not use VRC_Trigger in combination with deprecated event components.", MessageType.Error); + showedOldWarning = true; + } + VRCSDK2.VRC_EventHandler handler = t.GetComponent<VRCSDK2.VRC_EventHandler>(); + if (handler != null) + handler.Events = new List<VRCSDK2.VRC_EventHandler.VrcEvent>(); + } +#pragma warning restore CS0618 // Type or member is obsolete + + triggersProperty = serializedObject.FindProperty("Triggers"); + proximityProperty = serializedObject.FindProperty("proximity"); + interactTextProperty = serializedObject.FindProperty("interactText"); + ownershipProperty = serializedObject.FindProperty("TakesOwnershipIfNecessary"); + drawLinesProperty = serializedObject.FindProperty("DrawLines"); + + serializedObject.Update(); + + SerializedProperty triggers = triggersProperty.Copy(); + int triggersLength = triggers.arraySize; + + if (eventLists.Length != triggersLength) + eventLists = new ReorderableList[triggersLength]; + + if (relayLists.Length != triggersLength) + relayLists = new ReorderableList[triggersLength]; + + if (objectLists.Length != triggersLength) + objectLists = new ReorderableList[triggersLength]; + + if (visible.Length != triggersLength) + { + bool[] newVisible = new bool[triggersLength]; + for (int idx = 0; idx < visible.Length && idx < newVisible.Length; ++idx) + newVisible[idx] = visible[idx]; + for (int idx = visible.Length; idx < newVisible.Length && idx < newVisible.Length; ++idx) + newVisible[idx] = true; + visible = newVisible; + } + + EditorGUILayout.BeginVertical(GUILayout.MaxWidth(EditorGUIUtility.currentViewWidth - 30)); + + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(ownershipProperty, new GUIContent("Take Ownership of Action Targets")); + VRCSDK2.VRC_Trigger.EditorGlobalTriggerLineMode = (VRCSDK2.VRC_Trigger.EditorTriggerLineMode)EditorPrefs.GetInt("VRCSDK2_triggerLineMode", 0); + if (VRCSDK2.VRC_Trigger.EditorGlobalTriggerLineMode == VRCSDK2.VRC_Trigger.EditorTriggerLineMode.PerTrigger) + EditorGUILayout.PropertyField(drawLinesProperty, new GUIContent("Draw Lines")); + + EditorGUILayout.Space(); + + RenderTriggers(); + + EditorGUILayout.Space(); + + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(10); + EditorGUILayout.BeginVertical(); + + EditorGUILayout.EndVertical(); + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.EndVertical(); + + serializedObject.ApplyModifiedProperties(); + } + + private void RenderHelpBox(string message, MessageType messageType) + { + if (VRCSettings.DisplayHelpBoxes || messageType == MessageType.Error || messageType == MessageType.Warning) + EditorGUILayout.HelpBox(message, messageType); + } + + private void RenderTriggers() + { + GUIStyle triggerStyle = new GUIStyle(EditorStyles.helpBox); + + SerializedProperty triggers = triggersProperty.Copy(); + int triggersLength = triggers.arraySize; + + List<int> to_remove = new List<int>(); + for (int idx = 0; idx < triggersLength; ++idx) + { + SerializedProperty triggerProperty = triggers.GetArrayElementAtIndex(idx); + SerializedProperty broadcastProperty = triggerProperty.FindPropertyRelative("BroadcastType"); + + EditorGUILayout.BeginVertical(triggerStyle); + + if (RenderTriggerHeader(triggerProperty, ref visible[idx])) + { + to_remove.Add(idx); + EditorGUILayout.EndVertical(); + + continue; + } + + if (!visible[idx]) + { + EditorGUILayout.EndVertical(); + continue; + } + + if (!unbufferedBroadcastTypes.Contains((VRCSDK2.VRC_EventHandler.VrcBroadcastType)broadcastProperty.intValue) && + !bufferOneBroadcastTypes.Contains((VRCSDK2.VRC_EventHandler.VrcBroadcastType)broadcastProperty.intValue) && + ActiveEvents(triggerProperty).Any(e => e == VRCSDK2.VRC_EventHandler.VrcEventType.SendRPC)) + RenderHelpBox("Consider using unbuffered broadcasts with RPCs.", MessageType.Error); + + EditorGUILayout.Separator(); + + RenderTriggerEditor(triggerProperty, idx); + + if (eventLists.Length == triggersLength) + { + EditorGUILayout.Separator(); + + if (triggerProperty.FindPropertyRelative("TriggerType").intValue != (int)VRCSDK2.VRC_Trigger.TriggerType.Relay) + { + RenderTriggerEventsEditor(triggerProperty, idx); + + EditorGUILayout.Separator(); + } + } + EditorGUILayout.EndVertical(); + } + + foreach (int idx in ((IEnumerable<int>)to_remove).Reverse()) + triggersProperty.Copy().DeleteArrayElementAtIndex(idx); + + RenderAddTrigger(); + } + + private void RenderTriggerEditor(SerializedProperty triggerProperty, int idx) + { + EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("AfterSeconds"), new GUIContent("Delay in Seconds")); + + VRC_Trigger.TriggerType triggerType = (VRC_Trigger.TriggerType)triggerProperty.FindPropertyRelative("TriggerType").intValue; + switch (triggerType) + { + case VRCSDK2.VRC_Trigger.TriggerType.Custom: + RenderCustom(triggerProperty); + break; + case VRCSDK2.VRC_Trigger.TriggerType.Relay: + RenderRelay(triggerProperty, idx); + break; + case VRCSDK2.VRC_Trigger.TriggerType.OnEnterTrigger: + case VRCSDK2.VRC_Trigger.TriggerType.OnExitTrigger: + case VRCSDK2.VRC_Trigger.TriggerType.OnEnterCollider: + case VRCSDK2.VRC_Trigger.TriggerType.OnExitCollider: + RenderCollider(triggerProperty); + break; + case VRCSDK2.VRC_Trigger.TriggerType.OnKeyDown: + case VRCSDK2.VRC_Trigger.TriggerType.OnKeyUp: + RenderKey(triggerProperty); + break; + case VRCSDK2.VRC_Trigger.TriggerType.OnTimer: + RenderTimer(triggerProperty); + break; + case VRCSDK2.VRC_Trigger.TriggerType.OnDataStorageChange: + // case VRCSDK2.VRC_Trigger.TriggerType.OnDataStorageAdd: + // case VRCSDK2.VRC_Trigger.TriggerType.OnDataStorageRemove: + RenderDataStorage(triggerProperty); + break; + case VRCSDK2.VRC_Trigger.TriggerType.OnParticleCollision: + //RenderHelpBox("Triggers for each particle in attached particle system that collides with something.", MessageType.Info); + RenderCollider(triggerProperty); + break; + default: + if (VRCSDK2.VRC_Trigger.TypeCollections.InteractiveTypes.Contains(triggerType) || VRCSDK2.VRC_Trigger.TypeCollections.PickupTypes.Contains(triggerType)) + RenderInteractableEditor(); + else + RenderEmpty(triggerProperty); + break; + } + } + + private List<VRCSDK2.VRC_EventHandler.VrcEventType> ActiveEvents(SerializedProperty triggerProperty) + { + List<VRCSDK2.VRC_EventHandler.VrcEventType> activeTypes = new List<VRCSDK2.VRC_EventHandler.VrcEventType>(); + + SerializedProperty events = triggerProperty.FindPropertyRelative("Events").Copy(); + int eventsLength = events.arraySize; + + for (int idx = 0; idx < eventsLength; ++idx) + { + VRCSDK2.VRC_EventHandler.VrcEventType eventType = (VRCSDK2.VRC_EventHandler.VrcEventType)events.GetArrayElementAtIndex(idx).FindPropertyRelative("EventType").intValue; + activeTypes.Add(eventType); + } + + return activeTypes; + } + + private void RenderAddTrigger() + { + Rect rect = EditorGUILayout.BeginHorizontal(GUILayout.Height(15f)); + EditorGUILayout.Space(); + + Rect selectedRect = new Rect(rect.x, rect.y, rect.width / 4 * 3 - 5, rect.height); + Rect addRect = new Rect(selectedRect.x + selectedRect.width + 5, rect.y, rect.width / 4, rect.height); + + bool showStationTypes = serializedObject.targetObjects.Any(o => (o as VRCSDK2.VRC_Trigger).GetComponent<VRCSDK2.VRC_Station>() != null); + System.Func<VRCSDK2.VRC_Trigger.TriggerType, bool> predicate = + v => hiddenTriggerTypes.Contains(v) == false && (showStationTypes || (v != VRCSDK2.VRC_Trigger.TriggerType.OnStationEntered && v != VRCSDK2.VRC_Trigger.TriggerType.OnStationExited)); + + addTriggerSelectedType = VRC_EditorTools.FilteredEnumPopup(selectedRect, addTriggerSelectedType, predicate); + + if (GUI.Button(addRect, "Add")) + { + SerializedProperty triggersAry = triggersProperty; + + // hacks + triggersAry.Next(true); + triggersAry.Next(true); + + int triggersLength = triggersAry.intValue; + triggersAry.intValue = triggersLength + 1; + triggersAry.Next(true); + + for (int idx = 0; idx < triggersLength; ++idx) + triggersAry.Next(false); + + triggersAry.FindPropertyRelative("TriggerType").intValue = (int)addTriggerSelectedType; + triggersAry.FindPropertyRelative("BroadcastType").intValue = (int)VRCSDK2.VRC_EventHandler.VrcBroadcastType.AlwaysBufferOne; + triggersAry.FindPropertyRelative("TriggerIndividuals").boolValue = true; + triggersAry.FindPropertyRelative("Layers").intValue = LayerMask.GetMask("Default"); + } + + EditorGUILayout.EndHorizontal(); + } + + private bool RenderTriggerHeader(SerializedProperty triggerProperty, ref bool expand) + { + bool delete = false; + + if (!delete) + { + VRCSDK2.VRC_EventHandler.VrcBroadcastType? broadcast = null; + + Rect rect = EditorGUILayout.BeginHorizontal(GUILayout.Height(15f)); + EditorGUILayout.Space(); + + int baseWidth = (int)((rect.width - 40) / 4); + + Rect foldoutRect = new Rect(rect.x + 10, rect.y, 20, rect.height); + Rect typeRect = new Rect(rect.x + 20, rect.y, baseWidth, rect.height); + Rect broadcastRect = new Rect(rect.x + 25 + baseWidth, rect.y, baseWidth, rect.height); + Rect randomRect = new Rect(rect.x + 30 + baseWidth * 2, rect.y, baseWidth, rect.height); + Rect removeRect = new Rect(rect.x + 35 + baseWidth * 3, rect.y, baseWidth, rect.height); + + expand = EditorGUI.Foldout(foldoutRect, expand, GUIContent.none); + + SerializedProperty triggerTypeProperty = triggerProperty.FindPropertyRelative("TriggerType"); + VRCSDK2.VRC_Trigger.TriggerType currentType = (VRCSDK2.VRC_Trigger.TriggerType)triggerTypeProperty.intValue; + + SerializedProperty nameProperty = triggerProperty.FindPropertyRelative("Name"); + if (string.IsNullOrEmpty(nameProperty.stringValue)) + nameProperty.stringValue = "Unnamed"; + + bool showStationTypes = serializedObject.targetObjects.Any(o => (o as VRCSDK2.VRC_Trigger).GetComponent<VRCSDK2.VRC_Station>() != null); + System.Func<string, string> rename = s => s == "Custom" ? s + " (" + nameProperty.stringValue + ")" : s; + System.Func<VRCSDK2.VRC_Trigger.TriggerType, bool> predicate = + v => hiddenTriggerTypes.Contains(v) == false && (showStationTypes || (v != VRCSDK2.VRC_Trigger.TriggerType.OnStationEntered && v != VRCSDK2.VRC_Trigger.TriggerType.OnStationExited)); + + triggerTypeProperty.intValue = (int)VRC_EditorTools.FilteredEnumPopup(typeRect, currentType, predicate, rename); + currentType = (VRCSDK2.VRC_Trigger.TriggerType)triggerTypeProperty.intValue; + + SerializedProperty broadcastTypeProperty = triggerProperty.FindPropertyRelative("BroadcastType"); + List<VRCSDK2.VRC_EventHandler.VrcEventType> activeEvents = ActiveEvents(triggerProperty); + if ((VRCSDK2.VRC_Trigger.TriggerType)triggerTypeProperty.intValue == VRCSDK2.VRC_Trigger.TriggerType.Relay || activeEvents.Contains(VRCSDK2.VRC_EventHandler.VrcEventType.SpawnObject)) + { + broadcast = VRCSDK2.VRC_EventHandler.VrcBroadcastType.Always; + broadcastTypeProperty.intValue = (int)broadcast; + } + else + { + VRC_EditorTools.FilteredEnumPopup<VRCSDK2.VRC_EventHandler.VrcBroadcastType>(broadcastRect, broadcastTypeProperty, b => !hiddenBroadcastTypes.Contains(b)); + broadcast = (VRCSDK2.VRC_EventHandler.VrcBroadcastType)broadcastTypeProperty.intValue; + } + + SerializedProperty probabilitiesProperty = triggerProperty.FindPropertyRelative("Probabilities"); + SerializedProperty probabilityLockProperty = triggerProperty.FindPropertyRelative("ProbabilityLock"); + SerializedProperty eventsProperty = triggerProperty.FindPropertyRelative("Events"); + + if (triggerProperty.FindPropertyRelative("Events").arraySize < 1) + GUI.enabled = false; + if (GUI.Toggle(randomRect, probabilitiesProperty.arraySize > 0, new GUIContent(" Randomize"))) + probabilityLockProperty.arraySize = probabilitiesProperty.arraySize = eventsProperty.arraySize; + else + probabilityLockProperty.arraySize = probabilitiesProperty.arraySize = 0; + GUI.enabled = true; + + if (GUI.Button(removeRect, "Remove")) + delete = true; + + EditorGUILayout.EndHorizontal(); + + if (broadcast.HasValue && expand) + { + string message = null; + switch (broadcast.Value) + { + case VRCSDK2.VRC_EventHandler.VrcBroadcastType.Always: + message = "All are able to activate the trigger for everyone, and late-joiners will also trigger it."; + break; + case VRCSDK2.VRC_EventHandler.VrcBroadcastType.AlwaysUnbuffered: + message = "All are able to activate the trigger for everyone, but late-joiners will not trigger it."; + break; + case VRCSDK2.VRC_EventHandler.VrcBroadcastType.Local: + message = "All are able to activate the trigger for themselves only."; + break; + case VRCSDK2.VRC_EventHandler.VrcBroadcastType.Master: + message = "Only the Master is able to activate the trigger for everyone, and late-joiners will also trigger it."; + break; + case VRCSDK2.VRC_EventHandler.VrcBroadcastType.MasterUnbuffered: + message = "Only the Master is able to activate the trigger for everyone, but late-joiners will not trigger it."; + break; + case VRCSDK2.VRC_EventHandler.VrcBroadcastType.Owner: + message = "Only the Owner is able to activate the trigger for everyone, and late-joiners will also trigger it."; + break; + case VRCSDK2.VRC_EventHandler.VrcBroadcastType.OwnerUnbuffered: + message = "Only the Owner is able to activate the trigger for everyone, but late-joiners will not trigger it."; + break; + case VRCSDK2.VRC_EventHandler.VrcBroadcastType.AlwaysBufferOne: + message = "All are able to activate the trigger for everyone, and late-joiners will trigger the most recent one."; + break; + case VRCSDK2.VRC_EventHandler.VrcBroadcastType.MasterBufferOne: + message = "Only the Master is able to activate the trigger for everyone, and late-joiners will trigger the most recent one."; + break; + case VRCSDK2.VRC_EventHandler.VrcBroadcastType.OwnerBufferOne: + message = "Only the Owner is able to activate the trigger for everyone, and late-joiners will trigger the most recent one."; + break; + } + if (message != null) + RenderHelpBox(message, MessageType.Info); + } + } + + return delete; + } + + private void RenderInteractableEditor() + { + EditorGUILayout.PropertyField(interactTextProperty, new GUIContent("Interaction Text")); + proximityProperty.floatValue = EditorGUILayout.Slider("Proximity", proximityProperty.floatValue, 0f, 100f); + } + + private void RenderTriggerEventsEditor(SerializedProperty triggerProperty, int idx) + { + if (eventLists[idx] == null) + { + ReorderableList newList = new ReorderableList(serializedObject, triggerProperty.FindPropertyRelative("Events"), true, true, true, true); + newList.drawHeaderCallback = (Rect rect) => EditorGUI.LabelField(rect, "Actions"); + newList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => + { + SerializedProperty eventsListProperty = triggerProperty.FindPropertyRelative("Events"); + SerializedProperty probabilitiesProperty = triggerProperty.FindPropertyRelative("Probabilities"); + SerializedProperty probabilityLockProperty = triggerProperty.FindPropertyRelative("ProbabilityLock"); + SerializedProperty shadowListProperty = triggerProperty.FindPropertyRelative("DataStorageShadowValues"); + + if (shadowListProperty != null && shadowListProperty.arraySize != eventsListProperty.arraySize) + shadowListProperty.arraySize = eventsListProperty.arraySize; + + SerializedProperty shadowProperty = shadowListProperty == null ? null : shadowListProperty.GetArrayElementAtIndex(index); + SerializedProperty eventProperty = eventsListProperty.GetArrayElementAtIndex(index); + SerializedProperty eventTypeProperty = eventProperty.FindPropertyRelative("EventType"); + SerializedProperty parameterStringProperty = eventProperty.FindPropertyRelative("ParameterString"); + + string label = ((VRCSDK2.VRC_EventHandler.VrcEventType)eventTypeProperty.intValue).ToString(); + if (!string.IsNullOrEmpty(parameterStringProperty.stringValue)) + label += " (" + parameterStringProperty.stringValue + ")"; + + if (probabilitiesProperty.arraySize == 0) + EditorGUI.LabelField(rect, label); + else + { + Rect labelRect = new Rect(rect.x, rect.y, rect.width / 2, rect.height); + Rect sliderLockRect = new Rect(rect.x + rect.width / 2, rect.y, 30, rect.height); + Rect sliderRect = new Rect(rect.x + rect.width / 2 + 30, rect.y, rect.width / 2 - 30, rect.height); + + EditorGUI.LabelField(labelRect, label); + + probabilityLockProperty.GetArrayElementAtIndex(index).boolValue = GUI.Toggle(sliderLockRect, probabilityLockProperty.GetArrayElementAtIndex(index).boolValue, new GUIContent()); + probabilitiesProperty.GetArrayElementAtIndex(index).floatValue = EditorGUI.Slider(sliderRect, new GUIContent(), probabilitiesProperty.GetArrayElementAtIndex(index).floatValue, 0f, 1f); + + bool allLocked = true; + for (int pIdx = 0; pIdx < probabilitiesProperty.arraySize; ++pIdx) + allLocked = allLocked && probabilityLockProperty.GetArrayElementAtIndex(pIdx).boolValue; + if (allLocked) + for (int pIdx = 0; pIdx < probabilitiesProperty.arraySize; ++pIdx) + if (pIdx != index) + probabilitiesProperty.GetArrayElementAtIndex(pIdx).floatValue = probabilitiesProperty.GetArrayElementAtIndex(index).floatValue; + + // Squish 'em down + float probabilitySum = 1f; + const int MAX_SCALE_PROBABILITIES_LOOP_ITERATIONS = 8; + const int PROBABILITY_VALUE_DECIMAL_PLACES = 3; + int loopIterations = 0; + do + { + if (probabilitySum > 1f) + { + float fixRatio = 1f / probabilitySum; + int countChanged = 0; + for (int pIdx = 0; pIdx < probabilitiesProperty.arraySize; ++pIdx) + { + if (allLocked) + { + countChanged++; + probabilitiesProperty.GetArrayElementAtIndex(pIdx).floatValue *= fixRatio; + } + else + { + if (pIdx == index || probabilityLockProperty.GetArrayElementAtIndex(pIdx).boolValue || probabilitiesProperty.GetArrayElementAtIndex(pIdx).floatValue == 0f) + continue; + countChanged++; + probabilitiesProperty.GetArrayElementAtIndex(pIdx).floatValue *= fixRatio; + } + } + if (countChanged == 0) + probabilitiesProperty.GetArrayElementAtIndex(index).floatValue -= probabilitySum - 1f; + probabilitiesProperty.GetArrayElementAtIndex(index).floatValue = (float)Math.Round(probabilitiesProperty.GetArrayElementAtIndex(index).floatValue, PROBABILITY_VALUE_DECIMAL_PLACES); + } + probabilitySum = 0f; + for (int pIdx = 0; pIdx < probabilitiesProperty.arraySize; ++pIdx) + probabilitySum += probabilitiesProperty.GetArrayElementAtIndex(pIdx).floatValue; + loopIterations++; + } while ((probabilitySum > 1f) && (loopIterations < MAX_SCALE_PROBABILITIES_LOOP_ITERATIONS)); + } + + if (isFocused) + objectLists[idx] = null; + if (isActive) + { + EditorGUILayout.Space(); + + RenderEventEditor(shadowProperty, triggerProperty, eventProperty, idx); + } + }; + newList.onAddDropdownCallback = (Rect buttonRect, ReorderableList list) => + { + GenericMenu menu = new GenericMenu(); + SerializedProperty eventsList = triggerProperty.FindPropertyRelative("Events"); + foreach (VRCSDK2.VRC_EventHandler.VrcEventType type in System.Enum.GetValues(typeof(VRCSDK2.VRC_EventHandler.VrcEventType)).Cast<VRCSDK2.VRC_EventHandler.VrcEventType>().Where(v => !hiddenEventTypes.Contains(v)).OrderBy(et => System.Enum.GetName(typeof(VRCSDK2.VRC_EventHandler.VrcEventType), et))) + { + menu.AddItem(new GUIContent("Basic Events/" + type.ToString()), false, (t) => + { + eventsList.arraySize++; + + SerializedProperty newEventProperty = eventsList.GetArrayElementAtIndex(eventsList.arraySize - 1); + newEventProperty.FindPropertyRelative("EventType").intValue = (int)(VRCSDK2.VRC_EventHandler.VrcEventType)t; + newEventProperty.FindPropertyRelative("ParameterObjects").arraySize = 0; + newEventProperty.FindPropertyRelative("ParameterInt").intValue = 0; + newEventProperty.FindPropertyRelative("ParameterFloat").floatValue = 0f; + newEventProperty.FindPropertyRelative("ParameterString").stringValue = null; + + serializedObject.ApplyModifiedProperties(); + }, type); + } + VRC.SDKBase.IVRCEventProvider[] providers = FindObjectsOfType<MonoBehaviour>().Where(b => b is VRC.SDKBase.IVRCEventProvider).Cast<VRC.SDKBase.IVRCEventProvider>().ToArray(); + foreach (VRC.SDKBase.IVRCEventProvider provider in providers) + { + foreach (VRCSDK2.VRC_EventHandler.VrcEvent evt in provider.ProvideEvents()) + { + string name = "Events from Scene/" + (provider as MonoBehaviour).name + "/" + evt.Name; + menu.AddItem(new GUIContent(name), false, (t) => + { + eventsList.arraySize++; + + VRCSDK2.VRC_EventHandler.VrcEvent e = (VRCSDK2.VRC_EventHandler.VrcEvent)t; + + SerializedProperty newEventProperty = eventsList.GetArrayElementAtIndex(eventsList.arraySize - 1); + newEventProperty.FindPropertyRelative("Name").stringValue = e.Name; + newEventProperty.FindPropertyRelative("EventType").intValue = (int)e.EventType; + newEventProperty.FindPropertyRelative("ParameterInt").intValue = e.ParameterInt; + newEventProperty.FindPropertyRelative("ParameterFloat").floatValue = e.ParameterFloat; + newEventProperty.FindPropertyRelative("ParameterString").stringValue = e.ParameterString; + newEventProperty.FindPropertyRelative("ParameterObjects").arraySize = e.ParameterObjects.Length; + for (int obj_idx = 0; obj_idx < e.ParameterObjects.Length; ++obj_idx) + newEventProperty.FindPropertyRelative("ParameterObjects").GetArrayElementAtIndex(obj_idx).objectReferenceValue = e.ParameterObjects[obj_idx]; + +#pragma warning disable CS0618 // Type or member is obsolete + newEventProperty.FindPropertyRelative("ParameterObject").objectReferenceValue = e.ParameterObject; +#pragma warning restore CS0618 // Type or member is obsolete + + serializedObject.ApplyModifiedProperties(); + }, evt); + } + } + menu.ShowAsContext(); + + eventLists = new ReorderableList[0]; + objectLists = new ReorderableList[0]; + relayLists = new ReorderableList[0]; + }; + + eventLists[idx] = newList; + } + + ReorderableList eventList = eventLists[idx]; + eventList.DoLayoutList(); + } + + private void RenderDataStorage(SerializedProperty triggerProperty) + { + if (triggerProperty.serializedObject.targetObjects.Any(obj => (obj as VRCSDK2.VRC_Trigger).gameObject.GetComponent<VRCSDK2.VRC_DataStorage>() == null)) + RenderHelpBox("Data Storage Triggers require a VRC_DataStorage Component.", MessageType.Warning); + else + { + SerializedProperty idxProperty = triggerProperty.FindPropertyRelative("DataElementIdx"); + VRCSDK2.VRC_DataStorage ds = (target as VRCSDK2.VRC_Trigger).gameObject.GetComponent<VRCSDK2.VRC_DataStorage>(); + + if (ds.data == null) + { + ds.data = new VRCSDK2.VRC_DataStorage.VrcDataElement[0]; + idxProperty.intValue = -1; + } + + List<string> names = new List<string>(); + names.Add("Any Data Element"); + foreach (VRCSDK2.VRC_DataStorage.VrcDataElement element in ds.data) + names.Add(element.name); + + int selectedIdx = idxProperty.intValue; + if (selectedIdx == -1) + selectedIdx = 0; + else + selectedIdx += 1; + + selectedIdx = EditorGUILayout.Popup("Data Element", selectedIdx, names.ToArray()); + + if (selectedIdx == 0) + idxProperty.intValue = -1; + else + idxProperty.intValue = selectedIdx - 1; + } + } + + private void RenderKey(SerializedProperty triggerProperty) + { + EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("Key")); + } + + private void RenderCollider(SerializedProperty triggerProperty) + { + EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("TriggerIndividuals")); + EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("Layers")); + } + + private void RenderTimer(SerializedProperty triggerProperty) + { + EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("Repeat")); + EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("ResetOnEnable")); + EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("LowPeriodTime")); + EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("HighPeriodTime")); + } + + private void RenderCustom(SerializedProperty triggerProperty) + { + SerializedProperty nameProperty = triggerProperty.FindPropertyRelative("Name"); + EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("Name")); + + if (string.IsNullOrEmpty(nameProperty.stringValue)) + nameProperty.stringValue = "Unnamed"; + } + + private void RenderRelay(SerializedProperty triggerProperty, int idx) + { + if (relayLists[idx] == null) + { + ReorderableList newList = new ReorderableList(serializedObject, triggerProperty.FindPropertyRelative("Others"), true, true, true, true); + newList.drawHeaderCallback = (Rect rect) => EditorGUI.LabelField(rect, new GUIContent("Targets")); + newList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => + { + SerializedProperty target = newList.serializedProperty.GetArrayElementAtIndex(index); + + EditorGUI.PropertyField(rect, target, GUIContent.none); + + target.serializedObject.ApplyModifiedProperties(); + }; + relayLists[idx] = newList; + } + relayLists[idx].DoLayoutList(); + } + + private void RenderEmpty(SerializedProperty triggerProperty) + { + } + + private bool doesPropertyContainAnyNullReceivers(SerializedProperty objectsProperty) + { + bool containsNullReceivers = false; + if (objectsProperty.arraySize > 0) + { + for (int i = 0; i < objectsProperty.arraySize; i++) + { + SerializedProperty elem = objectsProperty.GetArrayElementAtIndex(i); + if (elem.objectReferenceValue == null) containsNullReceivers = true; + } + } + return containsNullReceivers; + } + + private void RenderTargetGameObjectList(SerializedProperty objectsProperty, int idx, bool receiverRequired = true) + { + if (objectLists[idx] == null) + { + objectLists[idx] = new ReorderableList(objectsProperty.serializedObject, objectsProperty, true, true, true, true); + objectLists[idx].drawHeaderCallback = (Rect rect) => + { + string infoString = "Receivers"; + if (objectsProperty.arraySize == 0) + infoString = "Receivers: This GameObject"; + EditorGUI.LabelField(rect, new GUIContent(infoString)); + + Event evt = Event.current; + if (!rect.Contains(evt.mousePosition)) + return; + + if (evt.type == EventType.DragUpdated) + DragAndDrop.visualMode = DragAndDropVisualMode.Copy; + if (evt.type == EventType.DragPerform) + { + GameObject[] dragObjects = DragAndDrop.objectReferences.OfType<GameObject>().ToArray(); + int startIndex = objectsProperty.arraySize; + objectsProperty.arraySize = objectsProperty.arraySize + dragObjects.Length; + + for (int i = 0; i < dragObjects.Length; i++) + { + SerializedProperty newElem = objectsProperty.GetArrayElementAtIndex(startIndex + i); + newElem.objectReferenceValue = dragObjects[i]; + } + + DragAndDrop.AcceptDrag(); + evt.Use(); + } + }; + objectLists[idx].drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => + { + SerializedProperty target = objectLists[idx].serializedProperty.GetArrayElementAtIndex(index); + EditorGUI.PropertyField(rect, target, GUIContent.none); + target.serializedObject.ApplyModifiedProperties(); + }; + } + objectLists[idx].DoLayoutList(); + if (objectsProperty.arraySize == 0) + RenderHelpBox("This trigger will target the GameObject it's on, because the receivers list is empty.", MessageType.Error); + else if (receiverRequired && doesPropertyContainAnyNullReceivers(objectsProperty)) + RenderHelpBox("Trigger with no object set will be ignored!", MessageType.Info); + } + + private void RenderTargetComponentList<T>(SerializedProperty objectsProperty, int idx, string label = "Receivers") where T : Component + { + if (objectLists[idx] == null) + { + objectLists[idx] = new ReorderableList(objectsProperty.serializedObject, objectsProperty, true, true, true, true); + objectLists[idx].drawHeaderCallback = (Rect rect) => + { + string infoString = label; + if (objectsProperty.arraySize == 0) + infoString = label + ": This " + typeof(T).Name; + EditorGUI.LabelField(rect, new GUIContent(infoString)); + + Event evt = Event.current; + if (!rect.Contains(evt.mousePosition)) + return; + + if (evt.type == EventType.DragUpdated) + DragAndDrop.visualMode = DragAndDropVisualMode.Copy; + if (evt.type == EventType.DragPerform) + { + GameObject[] dragObjects = DragAndDrop.objectReferences.OfType<GameObject>().ToArray(); + int startIndex = objectsProperty.arraySize; + objectsProperty.arraySize = objectsProperty.arraySize + dragObjects.Length; + + for (int i = 0; i < dragObjects.Length; i++) + { + SerializedProperty newElem = objectsProperty.GetArrayElementAtIndex(startIndex + i); + newElem.objectReferenceValue = dragObjects[i]; + } + + DragAndDrop.AcceptDrag(); + evt.Use(); + } + }; + objectLists[idx].drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => + { + SerializedProperty target = objectLists[idx].serializedProperty.GetArrayElementAtIndex(index); + + T current = null; + if (target.objectReferenceValue != null) + current = (target.objectReferenceValue as GameObject).GetComponent<T>(); + + current = EditorGUI.ObjectField(rect, current, typeof(T), true) as T; + target.objectReferenceValue = current == null ? null : current.gameObject; + target.serializedObject.ApplyModifiedProperties(); + }; + } + objectLists[idx].DoLayoutList(); + if (objectsProperty.arraySize == 0) + RenderHelpBox("This trigger will target the GameObject it's on, because the receivers list is empty.", MessageType.Error); + else if (doesPropertyContainAnyNullReceivers(objectsProperty)) + RenderHelpBox("Trigger with no object set will be ignored!", MessageType.Info); + } + + public void RenderEventEditor(SerializedProperty shadowProperty, SerializedProperty triggerProperty, SerializedProperty eventProperty, int triggerIdx) + { + SerializedProperty eventTypeProperty = eventProperty.FindPropertyRelative("EventType"); + SerializedProperty parameterObjectProperty = eventProperty.FindPropertyRelative("ParameterObject"); + SerializedProperty parameterObjectsProperty = eventProperty.FindPropertyRelative("ParameterObjects"); + SerializedProperty parameterStringProperty = eventProperty.FindPropertyRelative("ParameterString"); + SerializedProperty parameterBoolOpProperty = eventProperty.FindPropertyRelative("ParameterBoolOp"); + SerializedProperty parameterFloatProperty = eventProperty.FindPropertyRelative("ParameterFloat"); + SerializedProperty parameterIntProperty = eventProperty.FindPropertyRelative("ParameterInt"); + SerializedProperty parameterBytesProperty = eventProperty.FindPropertyRelative("ParameterBytes"); + + if (parameterObjectProperty.objectReferenceValue != null && parameterObjectsProperty.arraySize == 0) + { + parameterObjectsProperty.arraySize = 1; + parameterObjectsProperty.GetArrayElementAtIndex(0).objectReferenceValue = parameterObjectProperty.objectReferenceValue; + } + parameterObjectProperty.objectReferenceValue = null; + + switch ((VRCSDK2.VRC_EventHandler.VrcEventType)eventTypeProperty.intValue) + { + case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationBool: + { + RenderTargetComponentList<Animator>(parameterObjectsProperty, triggerIdx); + + RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("Variable")); + RenderPropertyEditor(shadowProperty, parameterBoolOpProperty, new GUIContent("Operation"), true); + break; + } + case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationFloat: + { + RenderTargetComponentList<Animator>(parameterObjectsProperty, triggerIdx); + + RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("Variable")); + RenderPropertyEditor(shadowProperty, parameterFloatProperty, new GUIContent("Value")); + break; + } + case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationInt: + case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationIntAdd: + case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationIntDivide: + case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationIntMultiply: + case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationIntSubtract: + { + RenderTargetComponentList<Animator>(parameterObjectsProperty, triggerIdx); + + RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("Variable")); + RenderPropertyEditor(shadowProperty, parameterIntProperty, new GUIContent("Value")); + break; + } + case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationTrigger: + { + RenderTargetComponentList<Animator>(parameterObjectsProperty, triggerIdx); + + RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("Trigger")); + break; + } + case VRCSDK2.VRC_EventHandler.VrcEventType.PlayAnimation: + { + RenderTargetComponentList<Animation>(parameterObjectsProperty, triggerIdx); + + RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("Clip")); + + for (int idx = 0; idx < parameterObjectsProperty.arraySize; ++idx) + { + GameObject obj = parameterObjectsProperty.GetArrayElementAtIndex(idx).objectReferenceValue as GameObject; + Animation anim = obj == null ? null : obj.GetComponent<Animation>(); + if (anim != null && anim.GetClip(parameterStringProperty.stringValue) == null) + { + RenderHelpBox("Could not locate " + parameterStringProperty.stringValue + " on " + obj.name + "; is it legacy?", MessageType.Error); + break; + } + } + break; + } + case VRCSDK2.VRC_EventHandler.VrcEventType.AudioTrigger: + { + RenderTargetComponentList<AudioSource>(parameterObjectsProperty, triggerIdx); + + List<string> clipNames = new List<string>(); + if (parameterObjectsProperty.arraySize > 0) + { + int idx = 0; + for (; idx < parameterObjectsProperty.arraySize; ++idx) + { + SerializedProperty prop = parameterObjectsProperty.GetArrayElementAtIndex(0); + GameObject obj = prop.objectReferenceValue != null ? prop.objectReferenceValue as GameObject : null; + if (obj != null) + { + foreach (AudioSource source in obj.GetComponents<AudioSource>()) + if (source.clip != null && !string.IsNullOrEmpty(source.clip.name)) + clipNames.Add(source.clip.name); + break; + } + } + for (; idx < parameterObjectsProperty.arraySize; ++idx) + { + SerializedProperty prop = parameterObjectsProperty.GetArrayElementAtIndex(0); + GameObject obj = prop.objectReferenceValue != null ? prop.objectReferenceValue as GameObject : null; + if (obj != null) + { + List<string> thisClipNames = new List<string>(); + foreach (AudioSource source in obj.GetComponents<AudioSource>()) + if (source.clip != null && !string.IsNullOrEmpty(source.clip.name)) + thisClipNames.Add(source.clip.name); + clipNames.RemoveAll(s => thisClipNames.Contains(s) == false); + } + } + } + + clipNames.Insert(0, ""); + int selectedIdx; + for (selectedIdx = clipNames.Count - 1; selectedIdx > 0; --selectedIdx) + if (parameterStringProperty.stringValue == clipNames[selectedIdx]) + break; + + parameterStringProperty.stringValue = clipNames[EditorGUILayout.Popup("Clip", selectedIdx, clipNames.ToArray())]; + break; + } +#pragma warning disable CS0618 // Type or member is obsolete + case VRCSDK2.VRC_EventHandler.VrcEventType.MeshVisibility: +#pragma warning restore CS0618 // Type or member is obsolete + { + RenderTargetComponentList<Renderer>(parameterObjectsProperty, triggerIdx); + RenderPropertyEditor(shadowProperty, parameterBoolOpProperty, new GUIContent("Operation"), true); + break; + } + case VRCSDK2.VRC_EventHandler.VrcEventType.RunConsoleCommand: + { + RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("Command")); + break; + } +#pragma warning disable CS0618 // Type or member is obsolete + case VRCSDK2.VRC_EventHandler.VrcEventType.SendMessage: +#pragma warning restore CS0618 // Type or member is obsolete + { + RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx); + if (parameterObjectsProperty.arraySize > 0) + RenderMethodSelector(eventProperty); + } + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.SetGameObjectActive: + { + RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx); + RenderPropertyEditor(shadowProperty, parameterBoolOpProperty, new GUIContent("Operation"), true); + break; + } + case VRCSDK2.VRC_EventHandler.VrcEventType.SetParticlePlaying: + { + RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx); + RenderPropertyEditor(shadowProperty, parameterBoolOpProperty, new GUIContent("Operation"), true); + break; + } + case VRCSDK2.VRC_EventHandler.VrcEventType.TeleportPlayer: + { + RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx); + RenderPropertyEditor(shadowProperty, parameterBoolOpProperty, new GUIContent("Align Room To Destination"), true); + parameterIntProperty.intValue = EditorGUILayout.Toggle("Lerp On Remote Clients", (parameterIntProperty.intValue != 0)) ? 1 : 0; + break; + } + case VRCSDK2.VRC_EventHandler.VrcEventType.SetWebPanelURI: + { + RenderTargetComponentList<VRCSDK2.VRC_WebPanel>(parameterObjectsProperty, triggerIdx); + RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("URI")); + break; + } + case VRCSDK2.VRC_EventHandler.VrcEventType.SetWebPanelVolume: + { + RenderTargetComponentList<VRCSDK2.VRC_WebPanel>(parameterObjectsProperty, triggerIdx); + parameterFloatProperty.floatValue = EditorGUILayout.Slider("Volume", parameterFloatProperty.floatValue, 0f, 1f); + break; + } + case VRCSDK2.VRC_EventHandler.VrcEventType.SendRPC: + { + RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx); + + if (parameterObjectsProperty.arraySize > 0) + { + RenderMethodSelector(eventProperty); + RenderRPCParameterEditor(eventProperty); + } + } + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.ActivateCustomTrigger: + { + RenderTargetComponentList<VRCSDK2.VRC_Trigger>(parameterObjectsProperty, triggerIdx); + + VRC_EditorTools.CustomTriggerPopup("Name", parameterObjectsProperty, parameterStringProperty); + } + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.SpawnObject: + { + VRCSDK2.VRC_SceneDescriptor scene = FindObjectOfType<VRCSDK2.VRC_SceneDescriptor>(); + + string path = parameterStringProperty.stringValue; + GameObject found = scene != null ? scene.DynamicPrefabs.FirstOrDefault(p => AssetDatabase.GetAssetOrScenePath(p) == path) : null; + found = found == null ? AssetDatabase.LoadAssetAtPath<GameObject>(path) : found; + GameObject newFound = EditorGUILayout.ObjectField("Prefab", found, typeof(GameObject), false) as GameObject; + parameterStringProperty.stringValue = newFound == null ? null : AssetDatabase.GetAssetOrScenePath(newFound); + + RenderTargetComponentList<Transform>(parameterObjectsProperty, triggerIdx, "Locations"); + } + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.DestroyObject: + { + SerializedProperty broadcastTypeProperty = triggerProperty.FindPropertyRelative("BroadcastType"); + VRCSDK2.VRC_EventHandler.VrcBroadcastType broadcast = (VRCSDK2.VRC_EventHandler.VrcBroadcastType)broadcastTypeProperty.intValue; + if (broadcast != VRCSDK2.VRC_EventHandler.VrcBroadcastType.Always && broadcast != VRCSDK2.VRC_EventHandler.VrcBroadcastType.AlwaysUnbuffered && broadcast != VRCSDK2.VRC_EventHandler.VrcBroadcastType.AlwaysBufferOne) + RenderHelpBox("Not all clients will destroy the object.", MessageType.Warning); + + RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx); + } + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.SetLayer: + { + RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx); + parameterIntProperty.intValue = (int)EditorGUILayout.LayerField("Layer", parameterIntProperty.intValue); + } + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.SetMaterial: + { + RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx); + + VRCSDK2.VRC_SceneDescriptor scene = FindObjectOfType<VRCSDK2.VRC_SceneDescriptor>(); + + string path = parameterStringProperty.stringValue; + Material found = scene != null ? scene.DynamicMaterials.FirstOrDefault(p => AssetDatabase.GetAssetOrScenePath(p) == path) : null; + found = found == null ? AssetDatabase.LoadAssetAtPath<Material>(path) : found; + Material newFound = EditorGUILayout.ObjectField("Material", found, typeof(Material), false) as Material; + parameterStringProperty.stringValue = newFound == null ? null : AssetDatabase.GetAssetOrScenePath(newFound); + + if (scene != null && found != newFound) + { + scene.DynamicMaterials.Add(newFound); + scene.DynamicMaterials.Remove(found); + } + } + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.AddDamage: + { + RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx, false); + RenderPropertyEditor(shadowProperty, parameterFloatProperty, new GUIContent("Damage")); + } + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.AddHealth: + { + RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx, false); + RenderPropertyEditor(shadowProperty, parameterFloatProperty, new GUIContent("Health")); + } + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.SetComponentActive: + { + RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx); + if (RenderTargetComponentEditor(parameterStringProperty, parameterObjectsProperty, triggerIdx)) + RenderPropertyEditor(shadowProperty, parameterBoolOpProperty, new GUIContent("Enable"), true); + } + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.AddVelocity: + case VRCSDK2.VRC_EventHandler.VrcEventType.SetVelocity: + { + RenderTargetComponentList<Rigidbody>(parameterObjectsProperty, triggerIdx); + RenderVector3andSpacePropertyEditor(parameterBytesProperty, new GUIContent("Velocity")); + } + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.AddAngularVelocity: + case VRCSDK2.VRC_EventHandler.VrcEventType.SetAngularVelocity: + { + RenderTargetComponentList<Rigidbody>(parameterObjectsProperty, triggerIdx); + RenderVector3andSpacePropertyEditor(parameterBytesProperty, new GUIContent("Angular Velocity")); + } + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.AddForce: + { + RenderTargetComponentList<Rigidbody>(parameterObjectsProperty, triggerIdx); + RenderVector3andSpacePropertyEditor(parameterBytesProperty, new GUIContent("Force")); + } + break; + case VRCSDK2.VRC_EventHandler.VrcEventType.SetUIText: + { + RenderTargetComponentList<Text>(parameterObjectsProperty, triggerIdx); + RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("Text")); + } + break; + +#if UDON + case VRCSDK2.VRC_EventHandler.VrcEventType.CallUdonMethod: + //{ + // RenderTargetComponentList<VRC.Udon.UdonBehaviour>(parameterObjectsProperty, triggerIdx); + // RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("Method Name")); + //} + break; +#endif + default: + RenderHelpBox("Unsupported event type", MessageType.Error); + break; + } + } + + private void RenderVector3andSpacePropertyEditor(SerializedProperty propertyBytes, GUIContent label) + { + object[] parameters = null; + parameters = VRC.SDKBase.VRC_Serialization.ParameterDecoder(VRC_EditorTools.ReadBytesFromProperty(propertyBytes)); + if (parameters.Length == 0) + parameters = new object[1] { new Vector4() }; + + EditorGUI.BeginChangeCheck(); + Vector3 vec3Field = EditorGUILayout.Vector3Field(label, new Vector3(((Vector4)parameters[0]).x, ((Vector4)parameters[0]).y, ((Vector4)parameters[0]).z)); + bool spaceField = EditorGUILayout.Toggle("Use World Space", ((Vector4)parameters[0]).w > .5f ? true : false); + parameters[0] = new Vector4(vec3Field.x, vec3Field.y, vec3Field.z, Convert.ToSingle(spaceField)); + if (EditorGUI.EndChangeCheck()) + { + VRC_EditorTools.WriteBytesToProperty(propertyBytes, VRC.SDKBase.VRC_Serialization.ParameterEncoder(parameters)); + } + } + + private void RenderVector3PropertyEditor(SerializedProperty propertyBytes, GUIContent label) + { + object[] parameters = null; + parameters = VRC.SDKBase.VRC_Serialization.ParameterDecoder(VRC_EditorTools.ReadBytesFromProperty(propertyBytes)); + if (parameters.Length == 0) + parameters = new object[1] { new Vector3() }; + + EditorGUI.BeginChangeCheck(); + parameters[0] = EditorGUILayout.Vector3Field(label, (Vector3)parameters[0]); + + if (EditorGUI.EndChangeCheck()) + { + VRC_EditorTools.WriteBytesToProperty(propertyBytes, VRC.SDKBase.VRC_Serialization.ParameterEncoder(parameters)); + } + } + + bool RenderTargetComponentEditor(SerializedProperty componentNameProperty, SerializedProperty objectsProperty, int triggerIdx) + { + if (!objectsProperty.isArray || objectsProperty.arraySize == 0) + return false; + + HashSet<Type> behaviours = new HashSet<Type>(); + bool isFirst = true; + for (int objIdx = 0; objIdx < objectsProperty.arraySize; ++objIdx) + { + if (objectsProperty.GetArrayElementAtIndex(objIdx) == null || objectsProperty.GetArrayElementAtIndex(objIdx).objectReferenceValue == null || !(objectsProperty.GetArrayElementAtIndex(objIdx).objectReferenceValue is GameObject)) + continue; + + if (isFirst) + { + foreach (Component component in (objectsProperty.GetArrayElementAtIndex(0).objectReferenceValue as GameObject).GetComponents(typeof(Component))) + { + Type t = component.GetType(); + if (t.GetProperty("enabled") != null) + behaviours.Add(component.GetType()); + } + isFirst = false; + } + else + { + HashSet<Type> thisBehaviours = new HashSet<Type>(); + foreach (Component component in (objectsProperty.GetArrayElementAtIndex(objIdx).objectReferenceValue as GameObject).GetComponents(typeof(Component))) + { + Type t = component.GetType(); + if (t.GetProperty("enabled") != null) + thisBehaviours.Add(component.GetType()); + } + behaviours.RemoveWhere(s => thisBehaviours.Contains(s) == false); + } + } + + if (behaviours.Count == 0) + return false; + + Type[] types = behaviours.ToArray(); + string[] options = behaviours.Select(t => t.FullName).ToArray(); + int selectedIdx = 0; + for (int typeIdx = 0; typeIdx < types.Length; ++typeIdx) + if (types[typeIdx].FullName == componentNameProperty.stringValue) + { + selectedIdx = typeIdx; + break; + } + + selectedIdx = EditorGUILayout.Popup("Component", selectedIdx, options); + componentNameProperty.stringValue = types[selectedIdx].FullName; + + return true; + } + + void RenderRPCParameterEditor(SerializedProperty eventProperty) + { + EditorGUI.BeginChangeCheck(); + + SerializedProperty parameterIntProperty = eventProperty.FindPropertyRelative("ParameterInt"); + SerializedProperty parameterObjectsProperty = eventProperty.FindPropertyRelative("ParameterObjects"); + SerializedProperty parameterStringProperty = eventProperty.FindPropertyRelative("ParameterString"); + SerializedProperty parameterBytesProperty = eventProperty.FindPropertyRelative("ParameterBytes"); + + if (parameterIntProperty.intValue == -1) + parameterIntProperty.intValue = (int)(VRCSDK2.VRC_EventHandler.VrcTargetType.All); + + parameterIntProperty.intValue = (int)VRC_EditorTools.FilteredEnumPopup<VRCSDK2.VRC_EventHandler.VrcTargetType>("Targets", (VRCSDK2.VRC_EventHandler.VrcTargetType)parameterIntProperty.intValue, e => e != VRCSDK2.VRC_EventHandler.VrcTargetType.TargetPlayer); + + string message = null; + switch ((VRCSDK2.VRC_EventHandler.VrcTargetType)parameterIntProperty.intValue) + { + case VRCSDK2.VRC_EventHandler.VrcTargetType.All: + message = "Will execute on all clients, except for those that join later."; + break; + case VRCSDK2.VRC_EventHandler.VrcTargetType.AllBuffered: + message = "Will execute on all clients, including those that join later."; + break; + case VRCSDK2.VRC_EventHandler.VrcTargetType.Local: + message = "Will execute for the instigator only."; + break; + case VRCSDK2.VRC_EventHandler.VrcTargetType.Master: + message = "Will execute on the Master."; + break; + case VRCSDK2.VRC_EventHandler.VrcTargetType.Others: + message = "Will execute for others but not locally, except for those that join later."; + break; + case VRCSDK2.VRC_EventHandler.VrcTargetType.OthersBuffered: + message = "Will execute for others but not locally, including those that join later."; + break; + case VRCSDK2.VRC_EventHandler.VrcTargetType.Owner: + message = "Will execute on the Owner."; + break; + case VRCSDK2.VRC_EventHandler.VrcTargetType.AllBufferOne: + message = "Will execute on all clients, and only the most recent is executed for those that join later."; + break; + case VRCSDK2.VRC_EventHandler.VrcTargetType.OthersBufferOne: + message = "Will execute for others but not locally, and only the most recent is executed for those that join later."; + break; + } + if (message != null) + RenderHelpBox(message, MessageType.Info); + + Dictionary<string, List<MethodInfo>> methods = VRC_EditorTools.GetSharedAccessibleMethodsOnGameObjects(parameterObjectsProperty); + if (methods.Count == 0) + { + RenderHelpBox("No applicable methods found.", MessageType.Error); + return; + } + + List<MethodInfo> methodInfos = methods.Values.Aggregate(new List<MethodInfo>(), (acc, lst) => { acc.AddRange(lst); return acc; }); + + MethodInfo info = methodInfos.FirstOrDefault(m => m.Name == parameterStringProperty.stringValue); + if (info == null) + return; + + ParameterInfo[] paramInfo = info.GetParameters(); + + // Editor-only + foreach (var p in paramInfo) + if (p.ParameterType.Namespace.StartsWith("VRCSDK2")) + VRC.SDKBase.VRC_Serialization.RegisterType(p.ParameterType); + + object[] parameters = null; + if (rpcByteCache.ContainsKey(eventProperty.propertyPath)) + parameters = rpcByteCache[eventProperty.propertyPath]; + else + { + parameters = VRC.SDKBase.VRC_Serialization.ParameterDecoder(VRC_EditorTools.ReadBytesFromProperty(parameterBytesProperty)); + rpcByteCache.Add(eventProperty.propertyPath, parameters); + } + + if (parameters == null) + parameters = new object[paramInfo.Length]; + if (parameters.Length != paramInfo.Length) + Array.Resize(ref parameters, paramInfo.Length); + + EditorGUI.BeginChangeCheck(); + + bool finalParamIsPlayer = false; + + for (int idx = 0; idx < parameters.Length; ++idx) + { + Type paramType = paramInfo[idx].ParameterType; + if (paramType == typeof(Color)) + { + if (parameters[idx] == null || parameters[idx].GetType() != paramType) + parameters[idx] = Color.black; + parameters[idx] = EditorGUILayout.ColorField(paramInfo[idx].Name, (Color)parameters[idx]); + } + else if (paramType == typeof(bool)) + { + if (parameters[idx] == null || parameters[idx].GetType() != paramType) + parameters[idx] = false; + parameters[idx] = EditorGUILayout.Toggle(paramInfo[idx].Name, (bool)parameters[idx]); + } + else if (paramType.IsEnum) + { + // make an array of strings of the enum values + var values = Enum.GetValues(paramType); + string[] itemStrings = new string[values.Length]; + int i = 0; + foreach (var item in Enum.GetValues(paramType)) + { + itemStrings[i++] = item.ToString(); + } + if (parameters[idx] == null || parameters[idx].GetType() != paramType) + parameters[idx] = Enum.Parse(paramType, itemStrings[0]); + parameters[idx] = Enum.Parse(paramType, itemStrings[EditorGUILayout.Popup(paramInfo[idx].Name, (int)parameters[idx], itemStrings)]); + } + else if (paramType == typeof(double)) + { + if (parameters[idx] == null || parameters[idx].GetType() != paramType) + parameters[idx] = 0d; + parameters[idx] = EditorGUILayout.DoubleField(paramInfo[idx].Name, (double)parameters[idx]); + } + else if (paramType == typeof(float)) + { + if (parameters[idx] == null || parameters[idx].GetType() != paramType) + parameters[idx] = 0f; + parameters[idx] = EditorGUILayout.FloatField(paramInfo[idx].Name, (float)parameters[idx]); + } + else if (paramType == typeof(int)) + { + if (parameters[idx] == null || parameters[idx].GetType() != paramType) + parameters[idx] = 0; + parameters[idx] = EditorGUILayout.IntField(paramInfo[idx].Name, (int)parameters[idx]); + } + else if (typeof(VRC.SDKBase.VRCPlayerApi).IsAssignableFrom(paramType)) + { + if (idx == parameters.Length - 1) + finalParamIsPlayer = true; + parameters[idx] = null; + } + else if (paramType == typeof(long)) + { + if (parameters[idx] == null || parameters[idx].GetType() != paramType) + parameters[idx] = 0; + parameters[idx] = EditorGUILayout.LongField(paramInfo[idx].Name, (long)parameters[idx]); + } + else if (paramType == typeof(UnityEngine.Rect)) + { + if (parameters[idx] == null || parameters[idx].GetType() != paramType) + parameters[idx] = new Rect(); + parameters[idx] = EditorGUILayout.RectField(paramInfo[idx].Name, (UnityEngine.Rect)parameters[idx]); + } + else if (paramType == typeof(string)) + { + if (parameters[idx] == null || parameters[idx].GetType() != paramType) + parameters[idx] = ""; + parameters[idx] = EditorGUILayout.TextField(paramInfo[idx].Name, (string)parameters[idx]); + } + else if (paramType == typeof(Vector2)) + { + if (parameters[idx] == null || parameters[idx].GetType() != paramType) + parameters[idx] = new Vector2(); + parameters[idx] = EditorGUILayout.Vector2Field(paramInfo[idx].Name, (Vector2)parameters[idx]); + } + else if (paramType == typeof(Vector3)) + { + if (parameters[idx] == null || parameters[idx].GetType() != paramType) + parameters[idx] = new Vector3(); + parameters[idx] = EditorGUILayout.Vector3Field(paramInfo[idx].Name, (Vector3)parameters[idx]); + } + else if (paramType == typeof(Vector4)) + { + if (parameters[idx] == null || parameters[idx].GetType() != paramType) + parameters[idx] = new Vector4(); + parameters[idx] = EditorGUILayout.Vector4Field(paramInfo[idx].Name, (Vector4)parameters[idx]); + } + else if (paramType == typeof(Quaternion)) + { + if (parameters[idx] == null || parameters[idx].GetType() != paramType) + parameters[idx] = new Quaternion(); + parameters[idx] = Quaternion.Euler(EditorGUILayout.Vector3Field(paramInfo[idx].Name, ((Quaternion)parameters[idx]).eulerAngles)); + } + else if (paramType == typeof(UnityEngine.Object) || paramType.IsSubclassOf(typeof(UnityEngine.Object))) + { + if (parameters[idx] != null && parameters[idx].GetType() != paramType) + parameters[idx] = null; + parameters[idx] = EditorGUILayout.ObjectField(paramInfo[idx].Name, (UnityEngine.Object)parameters[idx], paramType, true); + } + else + EditorGUILayout.LabelField("Unable to handle " + paramType.Name, EditorStyles.boldLabel); + } + + if (finalParamIsPlayer) + Array.Resize(ref parameters, parameters.Length - 1); + + if (EditorGUI.EndChangeCheck()) + { + VRC_EditorTools.WriteBytesToProperty(parameterBytesProperty, VRC.SDKBase.VRC_Serialization.ParameterEncoder(parameters)); + rpcByteCache[eventProperty.propertyPath] = parameters; + } + } + + void RenderMethodSelector(SerializedProperty eventProperty) + { + SerializedProperty parameterObjectsProperty = eventProperty.FindPropertyRelative("ParameterObjects"); + SerializedProperty parameterStringProperty = eventProperty.FindPropertyRelative("ParameterString"); + SerializedProperty parameterBytesProperty = eventProperty.FindPropertyRelative("ParameterBytes"); + + Dictionary<string, List<MethodInfo>> methods = VRC_EditorTools.GetSharedAccessibleMethodsOnGameObjects(parameterObjectsProperty); + if (methods.Count == 0) + return; + + List<string> combined = methods + .Select(pair => pair.Value.Select(s => pair.Key + "." + s.Name)) + .Aggregate((a, b) => + { + var v = new List<string>(); + v.AddRange(a); + v.AddRange(b); + return v; + }).ToList(); + combined.Insert(0, "Custom Method"); + + int currentIndex = string.IsNullOrEmpty(parameterStringProperty.stringValue) ? 0 : combined.FindIndex(s => + { + var split = s.Split('.'); + return split.Length > 1 && s.Split('.')[1] == parameterStringProperty.stringValue; + }); + if (currentIndex < 0 || currentIndex >= combined.Count) + currentIndex = 0; + + int newIndex = EditorGUILayout.Popup("Method", currentIndex, combined.ToArray()); + if (newIndex != currentIndex) + { + parameterStringProperty.stringValue = ""; + parameterBytesProperty.arraySize = 0; + } + currentIndex = newIndex; + + if (currentIndex == 0) + EditorGUILayout.PropertyField(parameterStringProperty, new GUIContent("Custom Method")); + else + parameterStringProperty.stringValue = combined[currentIndex].Split('.')[1]; + } + + private void RenderPropertyEditor(SerializedProperty shadowProperty, SerializedProperty property, GUIContent label, bool isBoolOp = false) + { + VRCSDK2.VRC_DataStorage ds = (target as VRCSDK2.VRC_Trigger).gameObject.GetComponent<VRCSDK2.VRC_DataStorage>(); + if (ds != null && ds.data != null && ds.data.Length != 0 && shadowProperty != null) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PrefixLabel(label); + + bool renderField = false; + switch (property.propertyType) + { + case SerializedPropertyType.Boolean: + { + SerializedProperty prop = shadowProperty.FindPropertyRelative("ParameterBoolOp"); + List<string> vals = ds.data.Where(el => el.type == VRCSDK2.VRC_DataStorage.VrcDataType.Bool).Select(el => el.name).ToList(); + renderField = !ListPopup(vals, prop); + } + break; + case SerializedPropertyType.Float: + { + SerializedProperty prop = shadowProperty.FindPropertyRelative("ParameterFloat"); + List<string> vals = ds.data.Where(el => el.type == VRCSDK2.VRC_DataStorage.VrcDataType.Float).Select(el => el.name).ToList(); + renderField = !ListPopup(vals, prop); + } + break; + case SerializedPropertyType.Integer: + { + SerializedProperty prop = shadowProperty.FindPropertyRelative("ParameterInt"); + List<string> vals = ds.data.Where(el => el.type == VRCSDK2.VRC_DataStorage.VrcDataType.Int).Select(el => el.name).ToList(); + renderField = !ListPopup(vals, prop); + } + break; + case SerializedPropertyType.String: + { + SerializedProperty prop = shadowProperty.FindPropertyRelative("ParameterString"); + List<string> vals = ds.data.Where(el => el.type == VRCSDK2.VRC_DataStorage.VrcDataType.String).Select(el => el.name).ToList(); + renderField = !ListPopup(vals, prop); + } + break; + default: + { + renderField = true; + } + break; + } + + if (renderField) + EditorGUILayout.PropertyField(property, GUIContent.none); + EditorGUILayout.EndHorizontal(); + } + else + { + if (isBoolOp) + VRC_EditorTools.FilteredEnumPopup<VRCSDK2.VRC_EventHandler.VrcBooleanOp>(label.text, property, s => s != VRCSDK2.VRC_EventHandler.VrcBooleanOp.Unused); + else + EditorGUILayout.PropertyField(property, label); + return; + } + } + + private bool ListPopup(List<string> vals, SerializedProperty prop, bool custom = true) + { + if (vals.Count == 0) + return false; + + if (custom) + vals.Insert(0, "Custom"); + + int selectedIdx = prop.stringValue == null ? 0 : vals.IndexOf(prop.stringValue); + if (selectedIdx < 0 || selectedIdx > vals.Count) + selectedIdx = 0; + + int idx = EditorGUILayout.Popup(selectedIdx, vals.ToArray()); + if (idx == 0 && custom) + { + prop.stringValue = null; + return false; + } + else + { + prop.stringValue = vals[idx]; + return true; + } + } + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_TriggerEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_TriggerEditor.cs.meta new file mode 100644 index 00000000..f108aeb7 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_TriggerEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3aecd666943878944a811acb9db2ace7 +timeCreated: 1474315179 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_WebPanelEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_WebPanelEditor.cs new file mode 100644 index 00000000..3f646e0a --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_WebPanelEditor.cs @@ -0,0 +1,215 @@ +#if VRC_SDK_VRCSDK2 && UNITY_EDITOR +using System.IO; +using UnityEditor; +using UnityEngine; +using UnityEditor.Build; +using System; +using System.Linq; +using VRC.SDKBase.Editor; + +namespace VRCSDK2 +{ + [CustomEditor(typeof(VRCSDK2.VRC_WebPanel))] + public class VRC_WebPanelEditor : UnityEditor.Editor + { + private void InspectorField(string propertyName, string humanName) + { + SerializedProperty propertyField = serializedObject.FindProperty(propertyName); + EditorGUILayout.PropertyField(propertyField, new GUIContent(humanName), true); + } + + bool showFiles = false; + System.Collections.Generic.List<string> directories = null; + System.Collections.Generic.List<string> files = null; + + public override void OnInspectorGUI() + { + serializedObject.Update(); + EditorGUI.BeginChangeCheck(); + + EditorGUILayout.BeginVertical(); + + EditorGUILayout.HelpBox("Do not play any videos with Web Panels, use VRC_SyncVideoPlayer instead!", MessageType.Error); + + EditorGUILayout.Space(); + + InspectorField("proximity", "Proximity for Interactivity"); + EditorGUILayout.Space(); + + VRCSDK2.VRC_WebPanel web = (VRCSDK2.VRC_WebPanel)target; + + if (Application.isPlaying) + { + InspectorField("webRoot", "Web Root"); + InspectorField("defaultUrl", "URI"); + + showFiles = web.webData != null && EditorGUILayout.Foldout(showFiles, web.webData.Count.ToString() + " files imported"); + if (showFiles) + foreach (var file in web.webData) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PrefixLabel(file.path); + EditorGUILayout.LabelField(file.data.Length.ToString()); + EditorGUILayout.EndHorizontal(); + } + } + else + { + SerializedProperty webRoot = serializedObject.FindProperty("webRoot"); + RenderDirectoryList(serializedObject, "webRoot", "Path To Web Content"); + + if (string.IsNullOrEmpty(webRoot.stringValue)) + { + InspectorField("defaultUrl", "Start URI"); + } + else + { + RenderWebRootSelector(serializedObject, "defaultUrl", "Start Page"); + + if (VRCSettings.DisplayHelpBoxes) + { + EditorGUILayout.HelpBox("Javascript API bindings are called with engine.call('methodName', ...), which returns a promise-like object.", MessageType.Info); + EditorGUILayout.HelpBox("Javascript may call ListBindings() to discover available API bindings.", MessageType.Info); + EditorGUILayout.HelpBox("Javascript may listen for the 'onBindingsReady' event to execute script when the page is fully loaded and API bindings are available.", MessageType.Info); + } + } + } + + EditorGUILayout.Space(); + + InspectorField("cookiesEnabled", "Enable Cookies"); + + InspectorField("interactive", "Is Interactive"); + + InspectorField("localOnly", "Only Visible Locally"); + + if (!web.localOnly) + { + InspectorField("syncURI", "Synchronize URI"); + InspectorField("syncInput", "Synchronize Mouse Position"); + } + + InspectorField("transparent", "Transparent Background"); + + InspectorField("autoFormSubmit", "Input should Submit Forms"); + + EditorGUILayout.Space(); + + InspectorField("station", "Interaction Station"); + EditorGUILayout.Space(); + + InspectorField("cursor", "Mouse Cursor Object"); + + EditorGUILayout.Space(); + + InspectorField("resolutionWidth", "Resolution Width"); + InspectorField("resolutionHeight", "Resolution Height"); + InspectorField("displayRegion", "Display Region"); + + EditorGUILayout.Space(); + + InspectorField("extraVideoScreens", "Duplicate Screens"); + + EditorGUILayout.EndVertical(); + + if (EditorGUI.EndChangeCheck()) + serializedObject.ApplyModifiedProperties(); + } + + private void AddSubDirectories(ref System.Collections.Generic.List<string> l, string root) + { + if (!Directory.Exists(root)) + { + return; + } + + if (!root.StartsWith(Application.dataPath + Path.DirectorySeparatorChar + "VRCSDK") + || root == Application.dataPath + Path.DirectorySeparatorChar + "VRCSDK" + Path.DirectorySeparatorChar + "Examples" + Path.DirectorySeparatorChar + "Sample Assets" + Path.DirectorySeparatorChar + "WebRoot") + l.Add(root.Substring(Application.dataPath.Length)); + + string[] subdirectories = Directory.GetDirectories(root); + foreach (string dir in subdirectories) + AddSubDirectories(ref l, dir); + } + + private void RenderDirectoryList(SerializedObject obj, string propertyName, string humanName) + { + if (directories == null) + { + directories = new System.Collections.Generic.List<string>(); + directories.Add("No Web Content Directory"); + + AddSubDirectories(ref directories, Application.dataPath + Path.DirectorySeparatorChar); + } + + SerializedProperty target = serializedObject.FindProperty(propertyName); + + int selectedIdx = target.stringValue == null ? 0 : directories.IndexOf(target.stringValue); + if (selectedIdx < 0 || selectedIdx >= directories.Count) + selectedIdx = 0; + + selectedIdx = EditorGUILayout.Popup(humanName, selectedIdx, directories.ToArray()); + if (selectedIdx > 0 && selectedIdx < directories.Count) + target.stringValue = directories[selectedIdx]; + else + target.stringValue = null; + } + + private void AddSubDirectoryFiles(ref System.Collections.Generic.List<string> l, string root) + { + if (!Directory.Exists(root)) + return; + + string[] files = Directory.GetFiles(root); + foreach (string file in files.Where(f => f.ToLower().EndsWith(".html") || f.ToLower().EndsWith(".htm"))) + l.Add(file.Substring(Application.dataPath.Length)); + + string[] subdirectories = Directory.GetDirectories(root); + foreach (string dir in subdirectories) + AddSubDirectoryFiles(ref l, dir); + } + + private void RenderWebRootSelector(SerializedObject obj, string propertyName, string humanName) + { + SerializedProperty webRoot = obj.FindProperty("webRoot"); + SerializedProperty target = serializedObject.FindProperty(propertyName); + + if (files == null) + { + files = new System.Collections.Generic.List<string>(); + + AddSubDirectoryFiles(ref files, Application.dataPath + webRoot.stringValue); + if (files.Count == 0) + { + EditorGUILayout.HelpBox("No suitable html files found in Web Content path.", MessageType.Error); + return; + } + } + + int selectedIdx = 0; + + try + { + System.Uri uri = string.IsNullOrEmpty(target.stringValue) ? null : new Uri(target.stringValue); + + selectedIdx = uri == null ? 0 : files.IndexOf(uri.AbsolutePath.Replace('/', System.IO.Path.DirectorySeparatorChar)); + if (selectedIdx < 0 || selectedIdx >= files.Count) + selectedIdx = 0; + } + catch { } + + selectedIdx = EditorGUILayout.Popup(humanName, selectedIdx, files.ToArray()); + if (selectedIdx >= 0 && selectedIdx < files.Count) + { + System.UriBuilder builder = new UriBuilder() + { + Scheme = "file", + Path = files[selectedIdx].Replace(System.IO.Path.DirectorySeparatorChar, '/'), + Host = "" + }; + target.stringValue = builder.Uri.ToString(); + } + } + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_WebPanelEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_WebPanelEditor.cs.meta new file mode 100644 index 00000000..06aa8999 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_WebPanelEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d09b36020f697be4d9a0f5a6a48cfa83 +timeCreated: 1457992191 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_YouTubeSyncEditor.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_YouTubeSyncEditor.cs new file mode 100644 index 00000000..0193737a --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_YouTubeSyncEditor.cs @@ -0,0 +1,20 @@ +#if UNITY_EDITOR && VRC_SDK_VRCSDK2 +using UnityEngine; +using UnityEditor; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.IO; + +namespace VRCSDK2 +{ + [CustomEditor(typeof(VRC_YouTubeSync))] + public class VRC_YouTubeSyncEditor : UnityEditor.Editor + { + public override void OnInspectorGUI() + { + EditorGUILayout.HelpBox("This component is deprecated, please use the VRC_SyncVideoPlayer component instead.", MessageType.Error); + } + } +} +#endif diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_YouTubeSyncEditor.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_YouTubeSyncEditor.cs.meta new file mode 100644 index 00000000..29cadd5d --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Components/VRC_YouTubeSyncEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 764e26c1ca28e2e45a30c778c1955a47 +timeCreated: 1474675311 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel.meta new file mode 100644 index 00000000..84fd980d --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 610a80e5f4a9dd448ad66750235b5c5e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/IVRCSdkControlPanelBuilder.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/IVRCSdkControlPanelBuilder.cs new file mode 100644 index 00000000..3dbb60d1 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/IVRCSdkControlPanelBuilder.cs @@ -0,0 +1,9 @@ + +public interface IVRCSdkControlPanelBuilder +{ + void ShowSettingsOptions(); + bool IsValidBuilder(out string message); + void ShowBuilder(); + void RegisterBuilder(VRCSdkControlPanel baseBuilder); + void SelectAllComponents(); +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/IVRCSdkControlPanelBuilder.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/IVRCSdkControlPanelBuilder.cs.meta new file mode 100644 index 00000000..685eb8e9 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/IVRCSdkControlPanelBuilder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 310a760e312f2984e85eece367bab19a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanel.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanel.cs new file mode 100644 index 00000000..b8e81972 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanel.cs @@ -0,0 +1,253 @@ +using UnityEditor; +using UnityEngine; +using VRC.Core; +using VRC.SDKBase.Editor; + +[ExecuteInEditMode] +public partial class VRCSdkControlPanel : EditorWindow +{ + public static VRCSdkControlPanel window; + + [MenuItem("VRChat SDK/Show Control Panel", false, 600)] + static void ShowControlPanel() + { + if (!ConfigManager.RemoteConfig.IsInitialized()) + { + VRC.Core.API.SetOnlineMode(true, "vrchat"); + ConfigManager.RemoteConfig.Init(() => ShowControlPanel()); + return; + } + + window = (VRCSdkControlPanel)EditorWindow.GetWindow(typeof(VRCSdkControlPanel)); + window.titleContent.text = "VRChat SDK"; + window.minSize = new Vector2(SdkWindowWidth + 4, 600); + window.maxSize = new Vector2(SdkWindowWidth + 4, 2000); + window.Init(); + window.Show(); + } + + public static GUIStyle titleGuiStyle; + public static GUIStyle boxGuiStyle; + public static GUIStyle infoGuiStyle; + public static GUIStyle listButtonStyleEven; + public static GUIStyle listButtonStyleOdd; + public static GUIStyle listButtonStyleSelected; + public static GUIStyle scrollViewSeparatorStyle; + public static GUIStyle searchBarStyle; + + void InitializeStyles() + { + titleGuiStyle = new GUIStyle(); + titleGuiStyle.fontSize = 15; + titleGuiStyle.fontStyle = FontStyle.BoldAndItalic; + titleGuiStyle.alignment = TextAnchor.MiddleCenter; + titleGuiStyle.wordWrap = true; + if (EditorGUIUtility.isProSkin) + titleGuiStyle.normal.textColor = Color.white; + else + titleGuiStyle.normal.textColor = Color.black; + + boxGuiStyle = new GUIStyle(); + if (EditorGUIUtility.isProSkin) + { + boxGuiStyle.normal.background = CreateBackgroundColorImage(new Color(0.3f, 0.3f, 0.3f)); + boxGuiStyle.normal.textColor = Color.white; + } + else + { + boxGuiStyle.normal.background = CreateBackgroundColorImage(new Color(0.85f, 0.85f, 0.85f)); + boxGuiStyle.normal.textColor = Color.black; + } + + infoGuiStyle = new GUIStyle(); + infoGuiStyle.wordWrap = true; ; + if (EditorGUIUtility.isProSkin) + infoGuiStyle.normal.textColor = Color.white; + else + infoGuiStyle.normal.textColor = Color.black; + infoGuiStyle.margin = new RectOffset(10, 10, 10, 10); + + listButtonStyleEven = new GUIStyle(); + listButtonStyleEven.margin = new RectOffset(0, 0, 0, 0); + listButtonStyleEven.border = new RectOffset(0, 0, 0, 0); + if (EditorGUIUtility.isProSkin) + { + listButtonStyleEven.normal.textColor = new Color(0.8f, 0.8f, 0.8f); + listButtonStyleEven.normal.background = CreateBackgroundColorImage(new Color(0.540f, 0.540f, 0.54f)); + } + else + { + listButtonStyleEven.normal.textColor = Color.black; + listButtonStyleEven.normal.background = CreateBackgroundColorImage(new Color(0.85f, 0.85f, 0.85f)); + } + + listButtonStyleOdd = new GUIStyle(); + listButtonStyleOdd.margin = new RectOffset(0, 0, 0, 0); + listButtonStyleOdd.border = new RectOffset(0, 0, 0, 0); + if (EditorGUIUtility.isProSkin) + { + listButtonStyleOdd.normal.textColor = new Color(0.8f, 0.8f, 0.8f); + //listButtonStyleOdd.normal.background = CreateBackgroundColorImage(new Color(0.50f, 0.50f, 0.50f)); + } + else + { + listButtonStyleOdd.normal.textColor = Color.black; + listButtonStyleOdd.normal.background = CreateBackgroundColorImage(new Color(0.90f, 0.90f, 0.90f)); + } + + listButtonStyleSelected = new GUIStyle(); + listButtonStyleSelected.normal.textColor = Color.white; + listButtonStyleSelected.margin = new RectOffset(0, 0, 0, 0); + if (EditorGUIUtility.isProSkin) + { + listButtonStyleSelected.normal.textColor = new Color(0.8f, 0.8f, 0.8f); + listButtonStyleSelected.normal.background = CreateBackgroundColorImage(new Color(0.4f, 0.4f, 0.4f)); + } + else + { + listButtonStyleSelected.normal.textColor = Color.black; + listButtonStyleSelected.normal.background = CreateBackgroundColorImage(new Color(0.75f, 0.75f, 0.75f)); + } + + scrollViewSeparatorStyle = new GUIStyle("Toolbar"); + scrollViewSeparatorStyle.fixedWidth = SdkWindowWidth + 10; + scrollViewSeparatorStyle.fixedHeight = 4; + scrollViewSeparatorStyle.margin.top = 1; + + searchBarStyle = new GUIStyle("Toolbar"); + searchBarStyle.fixedWidth = SdkWindowWidth; + searchBarStyle.fixedHeight = 23; + searchBarStyle.padding.top = 3; + + } + + void Init() + { + InitializeStyles(); + ResetIssues(); + InitAccount(); + } + + void OnEnable() + { + OnEnableAccount(); + AssemblyReloadEvents.afterAssemblyReload += BuilderAssemblyReload; + } + + void OnDisable() + { + AssemblyReloadEvents.afterAssemblyReload -= BuilderAssemblyReload; + } + + void OnDestroy() + { + AccountDestroy(); + } + + public const int SdkWindowWidth = 518; + + private readonly GUIContent[] _toolbarLabels = new GUIContent[4] + { + new GUIContent("Authentication"), + new GUIContent("Builder"), + new GUIContent("Content Manager"), + new GUIContent("Settings") + }; + + private readonly bool[] _toolbarOptionsLoggedIn = new bool[4] {true, true, true, true}; + private readonly bool[] _toolbarOptionsNotLoggedIn = new bool[4] {true, false, false, true}; + + void OnGUI() + { + if (window == null) + { + window = (VRCSdkControlPanel)EditorWindow.GetWindow(typeof(VRCSdkControlPanel)); + InitializeStyles(); + } + + if (_bannerImage == null) + _bannerImage = Resources.Load<Texture2D>("SDK_Panel_Banner"); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.BeginVertical(); + + GUILayout.Box(_bannerImage); + + if (Application.isPlaying) + { + GUI.enabled = false; + GUILayout.Space(20); + EditorGUILayout.LabelField("Unity Application is running ...\nStop it to access the Control Panel", titleGuiStyle, GUILayout.Width(SdkWindowWidth)); + GUI.enabled = true; + GUILayout.EndVertical(); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + return; + } + + EditorGUILayout.Space(); + + EnvConfig.SetActiveSDKDefines(); + + int showPanel = GUILayout.Toolbar(VRCSettings.ActiveWindowPanel, _toolbarLabels, APIUser.IsLoggedIn ? _toolbarOptionsLoggedIn : _toolbarOptionsNotLoggedIn, null, GUILayout.Width(SdkWindowWidth)); + + // Only show Account or Settings panels if not logged in + if (APIUser.IsLoggedIn == false && showPanel != 3) + { + showPanel = 0; + } + + if (showPanel != VRCSettings.ActiveWindowPanel) + { + VRCSettings.ActiveWindowPanel = showPanel; + } + + GUILayout.EndVertical(); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + switch (showPanel) + { + case 1: + ShowBuilders(); + break; + case 2: + ShowContent(); + break; + case 3: + ShowSettings(); + break; + case 0: + default: + ShowAccount(); + break; + } + } + + [UnityEditor.Callbacks.PostProcessScene] + static void OnPostProcessScene() + { + if (window != null) + window.Reset(); + } + + private void OnFocus() + { + Reset(); + } + + public void Reset() + { + ResetIssues(); + // style backgrounds may be nulled on scene load. detect if so has happened + if((boxGuiStyle != null) && (boxGuiStyle.normal.background == null)) + InitializeStyles(); + } + + [UnityEditor.Callbacks.DidReloadScripts(int.MaxValue)] + static void DidReloadScripts() + { + RefreshApiUrlSetting(); + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanel.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanel.cs.meta new file mode 100644 index 00000000..2602c029 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanel.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 20b4cdbdda9655947aab6f8f2c90690f +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelAccount.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelAccount.cs new file mode 100644 index 00000000..0e96a6a4 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelAccount.cs @@ -0,0 +1,551 @@ +using UnityEngine; +using UnityEditor; +using VRC.Core; +using System.Text.RegularExpressions; +using VRC.SDKBase.Editor; + +public partial class VRCSdkControlPanel : EditorWindow +{ + static bool isInitialized = false; + static string clientInstallPath; + static bool signingIn = false; + static string error = null; + + public static bool FutureProofPublishEnabled { get { return UnityEditor.EditorPrefs.GetBool("futureProofPublish", DefaultFutureProofPublishEnabled); } } + //public static bool DefaultFutureProofPublishEnabled { get { return !SDKClientUtilities.IsInternalSDK(); } } + public static bool DefaultFutureProofPublishEnabled { get { return false; } } + + static string storedUsername + { + get + { + return null; + } + set + { + EditorPrefs.DeleteKey("sdk#username"); + } + } + + static string storedPassword + { + get + { + return null; + } + set + { + EditorPrefs.DeleteKey("sdk#password"); + } + } + + static string username { get; set; } = null; + static string password { get; set; } = null; + + static ApiServerEnvironment serverEnvironment + { + get + { + ApiServerEnvironment env = ApiServerEnvironment.Release; + try + { + env = (ApiServerEnvironment)System.Enum.Parse(typeof(ApiServerEnvironment), UnityEditor.EditorPrefs.GetString("VRC_ApiServerEnvironment", env.ToString())); + } + catch (System.Exception e) + { + Debug.LogError("Invalid server environment name - " + e.ToString()); + } + + return env; + } + set + { + UnityEditor.EditorPrefs.SetString("VRC_ApiServerEnvironment", value.ToString()); + + API.SetApiUrlFromEnvironment(value); + } + } + + private void OnEnableAccount() + { + entered2faCodeIsInvalid = false; + warningIconGraphic = Resources.Load("2FAIcons/SDK_Warning_Triangle_icon") as Texture2D; + } + + public static void RefreshApiUrlSetting() + { + // this forces the static api url variable to be reset from the server environment set in editor prefs. + // needed because the static variable states get cleared when entering / exiting play mode + ApiServerEnvironment env = serverEnvironment; + serverEnvironment = env; + } + + public static void InitAccount() + { + if (isInitialized) + return; + + if (!APIUser.IsLoggedIn && ApiCredentials.Load()) + APIUser.InitialFetchCurrentUser((c) => AnalyticsSDK.LoggedInUserChanged(c.Model as APIUser), null); + + clientInstallPath = SDKClientUtilities.GetSavedVRCInstallPath(); + if (string.IsNullOrEmpty(clientInstallPath)) + clientInstallPath = SDKClientUtilities.LoadRegistryVRCInstallPath(); + + signingIn = false; + isInitialized = true; + + ClearContent(); + } + + public static bool OnShowStatus() + { + API.SetOnlineMode(true); + + SignIn(false); + + EditorGUILayout.BeginVertical(); + + if (APIUser.IsLoggedIn) + { + OnCreatorStatusGUI(); + } + + EditorGUILayout.EndVertical(); + + return APIUser.IsLoggedIn; + } + + static bool OnAccountGUI() + { + const int ACCOUNT_LOGIN_BORDER_SPACING = 20; + + EditorGUILayout.Separator(); + EditorGUILayout.Separator(); + EditorGUILayout.Separator(); + EditorGUILayout.Separator(); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.Space(ACCOUNT_LOGIN_BORDER_SPACING); + GUILayout.BeginVertical("Account", "window", GUILayout.Height(150), GUILayout.Width(340)); + + if (signingIn) + { + EditorGUILayout.LabelField("Signing in as " + username + "."); + } + else if (APIUser.IsLoggedIn) + { + if (Status != "Connected") + EditorGUILayout.LabelField(Status); + + OnCreatorStatusGUI(); + + GUILayout.BeginHorizontal(); + GUILayout.Label(""); + + if (GUILayout.Button("Logout")) + { + storedUsername = username = null; + storedPassword = password = null; + + VRC.Tools.ClearCookies(); + APIUser.Logout(); + ClearContent(); + } + GUILayout.EndHorizontal(); + } + else + { + InitAccount(); + + ApiServerEnvironment newEnv = ApiServerEnvironment.Release; + if (VRCSettings.DisplayAdvancedSettings) + newEnv = (ApiServerEnvironment)EditorGUILayout.EnumPopup("Use API", serverEnvironment); + if (serverEnvironment != newEnv) + serverEnvironment = newEnv; + + username = EditorGUILayout.TextField("Username/Email", username); + password = EditorGUILayout.PasswordField("Password", password); + + if (GUILayout.Button("Sign In")) + SignIn(true); + if (GUILayout.Button("Sign up")) + Application.OpenURL("https://vrchat.com/register"); + } + + if (showTwoFactorAuthenticationEntry) + { + OnTwoFactorAuthenticationGUI(); + } + + GUILayout.EndVertical(); + GUILayout.Space(ACCOUNT_LOGIN_BORDER_SPACING); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + return !signingIn; + } + + static void OnCreatorStatusGUI() + { + EditorGUILayout.LabelField("Logged in as:", APIUser.CurrentUser.displayName); + + //if (SDKClientUtilities.IsInternalSDK()) + // EditorGUILayout.LabelField("Developer Status: ", APIUser.CurrentUser.developerType.ToString()); + + EditorGUILayout.BeginHorizontal(); + + EditorGUILayout.BeginVertical(); + EditorGUILayout.LabelField("World Creator Status: ", APIUser.CurrentUser.canPublishWorlds ? "Allowed to publish worlds" : "Not yet allowed to publish worlds"); + EditorGUILayout.LabelField("Avatar Creator Status: ", APIUser.CurrentUser.canPublishAvatars ? "Allowed to publish avatars" : "Not yet allowed to publish avatars"); + EditorGUILayout.EndVertical(); + + if (!APIUser.CurrentUser.canPublishAllContent) + { + if (GUILayout.Button("More Info...")) + { + VRCSdkControlPanel.ShowContentPublishPermissionsDialog(); + } + } + + + EditorGUILayout.EndHorizontal(); + } + + void ShowAccount() + { + if (VRC.Core.ConfigManager.RemoteConfig.IsInitialized()) + { + if (VRC.Core.ConfigManager.RemoteConfig.HasKey("sdkUnityVersion")) + { + string sdkUnityVersion = VRC.Core.ConfigManager.RemoteConfig.GetString("sdkUnityVersion"); + if (string.IsNullOrEmpty(sdkUnityVersion)) + EditorGUILayout.LabelField("Could not fetch remote config."); + else if (Application.unityVersion != sdkUnityVersion) + { + EditorGUILayout.LabelField("Unity Version", EditorStyles.boldLabel); + EditorGUILayout.LabelField("Wrong Unity version. Please use " + sdkUnityVersion); + } + } + } + else + { + VRC.Core.API.SetOnlineMode(true, "vrchat"); + VRC.Core.ConfigManager.RemoteConfig.Init(); + } + + OnAccountGUI(); + } + + + private const string TWO_FACTOR_AUTHENTICATION_HELP_URL = "https://docs.vrchat.com/docs/setup-2fa"; + + private const string ENTER_2FA_CODE_TITLE_STRING = "Enter a numeric code from your authenticator app (or one of your saved recovery codes)."; + private const string ENTER_2FA_CODE_LABEL_STRING = "Code:"; + + private const string CHECKING_2FA_CODE_STRING = "Checking code..."; + private const string ENTER_2FA_CODE_INVALID_CODE_STRING = "Invalid Code"; + + private const string ENTER_2FA_CODE_VERIFY_STRING = "Verify"; + private const string ENTER_2FA_CODE_CANCEL_STRING = "Cancel"; + private const string ENTER_2FA_CODE_HELP_STRING = "Help"; + + private const int WARNING_ICON_SIZE = 60; + private const int WARNING_FONT_HEIGHT = 18; + + static private Texture2D warningIconGraphic; + + static bool entered2faCodeIsInvalid; + static bool authorizationCodeWasVerified; + + static private int previousAuthenticationCodeLength = 0; + static bool checkingCode; + static string authenticationCode = ""; + + static System.Action onAuthenticationVerifiedAction; + + static bool _showTwoFactorAuthenticationEntry = false; + + static bool showTwoFactorAuthenticationEntry + { + get + { + return _showTwoFactorAuthenticationEntry; + } + set + { + _showTwoFactorAuthenticationEntry = value; + authenticationCode = ""; + if (!_showTwoFactorAuthenticationEntry && !authorizationCodeWasVerified) + Logout(); + } + } + + static bool IsValidAuthenticationCodeFormat() + { + bool isValid2faAuthenticationCode = false; + + if (!string.IsNullOrEmpty(authenticationCode)) + { + // check if the input is a valid 6-digit numberic code (ignoring spaces) + Regex rx = new Regex(@"^(\s*\d\s*){6}$", RegexOptions.Compiled); + MatchCollection matches6DigitCode = rx.Matches(authenticationCode); + isValid2faAuthenticationCode = (matches6DigitCode.Count == 1); + } + + return isValid2faAuthenticationCode; + } + + static bool IsValidRecoveryCodeFormat() + { + bool isValid2faRecoveryCode = false; + + if (!string.IsNullOrEmpty(authenticationCode)) + { + // check if the input is a valid 8-digit alpha-numberic code (format xxxx-xxxx) "-" is optional & ignore any spaces + // OTP codes also exclude the letters i,l,o and the digit 1 to prevent any confusion + Regex rx = new Regex(@"^(\s*[a-hj-km-np-zA-HJ-KM-NP-Z02-9]\s*){4}-?(\s*[a-hj-km-np-zA-HJ-KM-NP-Z02-9]\s*){4}$", RegexOptions.Compiled); + MatchCollection matchesRecoveryCode = rx.Matches(authenticationCode); + isValid2faRecoveryCode = (matchesRecoveryCode.Count == 1); + } + + return isValid2faRecoveryCode; + } + + static void OnTwoFactorAuthenticationGUI() + { + const int ENTER_2FA_CODE_BORDER_SIZE = 20; + const int ENTER_2FA_CODE_BUTTON_WIDTH = 260; + const int ENTER_2FA_CODE_VERIFY_BUTTON_WIDTH = ENTER_2FA_CODE_BUTTON_WIDTH / 2; + const int ENTER_2FA_CODE_ENTRY_REGION_WIDTH = 130; + const int ENTER_2FA_CODE_MIN_WINDOW_WIDTH = ENTER_2FA_CODE_VERIFY_BUTTON_WIDTH + ENTER_2FA_CODE_ENTRY_REGION_WIDTH + (ENTER_2FA_CODE_BORDER_SIZE * 3); + + bool isValidAuthenticationCode = IsValidAuthenticationCodeFormat(); + + + // Invalid code text + if (entered2faCodeIsInvalid) + { + GUIStyle s = new GUIStyle(EditorStyles.label); + s.alignment = TextAnchor.UpperLeft; + s.normal.textColor = Color.red; + s.fontSize = WARNING_FONT_HEIGHT; + s.padding = new RectOffset(0, 0, (WARNING_ICON_SIZE - s.fontSize) / 2, 0); + s.fixedHeight = WARNING_ICON_SIZE; + + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + + EditorGUILayout.BeginVertical(); + GUILayout.FlexibleSpace(); + EditorGUILayout.BeginHorizontal(); + var textDimensions = s.CalcSize(new GUIContent(ENTER_2FA_CODE_INVALID_CODE_STRING)); + GUILayout.Label(new GUIContent(warningIconGraphic), GUILayout.Width(WARNING_ICON_SIZE), GUILayout.Height(WARNING_ICON_SIZE)); + EditorGUILayout.LabelField(ENTER_2FA_CODE_INVALID_CODE_STRING, s, GUILayout.Width(textDimensions.x)); + EditorGUILayout.EndHorizontal(); + GUILayout.FlexibleSpace(); + EditorGUILayout.EndVertical(); + + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + } + else if (checkingCode) + { + // Display checking code message + EditorGUILayout.BeginVertical(); + GUILayout.FlexibleSpace(); + EditorGUILayout.BeginHorizontal(); + GUIStyle s = new GUIStyle(EditorStyles.label); + s.alignment = TextAnchor.MiddleCenter; + s.fixedHeight = WARNING_ICON_SIZE; + EditorGUILayout.LabelField(CHECKING_2FA_CODE_STRING, s, GUILayout.Height(WARNING_ICON_SIZE)); + EditorGUILayout.EndHorizontal(); + GUILayout.FlexibleSpace(); + EditorGUILayout.EndVertical(); + } + else + { + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(ENTER_2FA_CODE_BORDER_SIZE); + GUILayout.FlexibleSpace(); + GUIStyle titleStyle = new GUIStyle(EditorStyles.label); + titleStyle.alignment = TextAnchor.MiddleCenter; + titleStyle.wordWrap = true; + EditorGUILayout.LabelField(ENTER_2FA_CODE_TITLE_STRING, titleStyle, GUILayout.Width(ENTER_2FA_CODE_MIN_WINDOW_WIDTH - (2 * ENTER_2FA_CODE_BORDER_SIZE)), GUILayout.Height(WARNING_ICON_SIZE), GUILayout.ExpandHeight(true)); + GUILayout.FlexibleSpace(); + GUILayout.Space(ENTER_2FA_CODE_BORDER_SIZE); + EditorGUILayout.EndHorizontal(); + } + + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(ENTER_2FA_CODE_BORDER_SIZE); + GUILayout.FlexibleSpace(); + Vector2 size = EditorStyles.boldLabel.CalcSize(new GUIContent(ENTER_2FA_CODE_LABEL_STRING)); + EditorGUILayout.LabelField(ENTER_2FA_CODE_LABEL_STRING, EditorStyles.boldLabel, GUILayout.MaxWidth(size.x)); + authenticationCode = EditorGUILayout.TextField(authenticationCode); + + // Verify 2FA code button + if (GUILayout.Button(ENTER_2FA_CODE_VERIFY_STRING, GUILayout.Width(ENTER_2FA_CODE_VERIFY_BUTTON_WIDTH))) + { + checkingCode = true; + APIUser.VerifyTwoFactorAuthCode(authenticationCode, isValidAuthenticationCode ? API2FA.TIME_BASED_ONE_TIME_PASSWORD_AUTHENTICATION : API2FA.ONE_TIME_PASSWORD_AUTHENTICATION, username, password, + delegate + { + // valid 2FA code submitted + entered2faCodeIsInvalid = false; + authorizationCodeWasVerified = true; + checkingCode = false; + showTwoFactorAuthenticationEntry = false; + if (null != onAuthenticationVerifiedAction) + onAuthenticationVerifiedAction(); + }, + delegate + { + entered2faCodeIsInvalid = true; + checkingCode = false; + } + ); + } + + GUILayout.FlexibleSpace(); + GUILayout.Space(ENTER_2FA_CODE_BORDER_SIZE); + EditorGUILayout.EndHorizontal(); + + GUILayout.FlexibleSpace(); + + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + + // after user has entered an invalid code causing the invalid code message to be displayed, + // edit the code will change it's length meaning it is invalid format, so we can clear the invalid code setting until they resubmit + if (previousAuthenticationCodeLength != authenticationCode.Length) + { + previousAuthenticationCodeLength = authenticationCode.Length; + entered2faCodeIsInvalid = false; + } + + GUI.enabled = true; + GUILayout.FlexibleSpace(); + GUILayout.Space(ENTER_2FA_CODE_BORDER_SIZE); + EditorGUILayout.EndHorizontal(); + + GUILayout.FlexibleSpace(); + + // Two-Factor Authentication Help button + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button(ENTER_2FA_CODE_HELP_STRING)) + { + Application.OpenURL(TWO_FACTOR_AUTHENTICATION_HELP_URL); + } + EditorGUILayout.EndHorizontal(); + + // Cancel button + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button(ENTER_2FA_CODE_CANCEL_STRING)) + { + showTwoFactorAuthenticationEntry = false; + Logout(); + } + EditorGUILayout.EndHorizontal(); + } + + private static string Status + { + get + { + if (!APIUser.IsLoggedIn) + return error == null ? "Please log in." : "Error in authenticating: " + error; + if (signingIn) + return "Logging in."; + else + { + if( serverEnvironment == ApiServerEnvironment.Dev ) + return "Connected to " + serverEnvironment.ToString(); + return "Connected"; + } + } + } + + private static void OnAuthenticationCompleted() + { + AttemptLogin(); + } + + private static void AttemptLogin() + { + APIUser.Login(username, password, + delegate (ApiModelContainer<APIUser> c) + { + APIUser user = c.Model as APIUser; + if (c.Cookies.ContainsKey("twoFactorAuth")) + ApiCredentials.Set(user.username, username, "vrchat", c.Cookies["auth"], c.Cookies["twoFactorAuth"]); + else if (c.Cookies.ContainsKey("auth")) + ApiCredentials.Set(user.username, username, "vrchat", c.Cookies["auth"]); + else + ApiCredentials.SetHumanName(user.username); + signingIn = false; + error = null; + storedUsername = null; + storedPassword = null; + AnalyticsSDK.LoggedInUserChanged(user); + + if (!APIUser.CurrentUser.canPublishAllContent) + { + if (UnityEditor.SessionState.GetString("HasShownContentPublishPermissionsDialogForUser", "") != user.id) + { + UnityEditor.SessionState.SetString("HasShownContentPublishPermissionsDialogForUser", user.id); + VRCSdkControlPanel.ShowContentPublishPermissionsDialog(); + } + } + }, + delegate (ApiModelContainer<APIUser> c) + { + Logout(); + error = c.Error; + VRC.Core.Logger.Log("Error logging in: " + error); + }, + delegate (ApiModelContainer<API2FA> c) + { + if (c.Cookies.ContainsKey("auth")) + ApiCredentials.Set(username, username, "vrchat", c.Cookies["auth"]); + showTwoFactorAuthenticationEntry = true; + onAuthenticationVerifiedAction = OnAuthenticationCompleted; + } + ); + } + + + private static object syncObject = new object(); + private static void SignIn(bool explicitAttempt) + { + lock (syncObject) + { + if (signingIn + || APIUser.IsLoggedIn + || (!explicitAttempt && string.IsNullOrEmpty(storedUsername))) + return; + + signingIn = true; + } + + InitAccount(); + + AttemptLogin(); + } + + public static void Logout() + { + signingIn = false; + storedUsername = null; + storedPassword = null; + VRC.Tools.ClearCookies(); + APIUser.Logout(); + } + + private void AccountDestroy() + { + signingIn = false; + isInitialized = false; + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelAccount.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelAccount.cs.meta new file mode 100644 index 00000000..33a77121 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelAccount.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5066cd5c1cc208143a1253cac821714a +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelAvatarBuilder.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelAvatarBuilder.cs new file mode 100644 index 00000000..9efdbc2d --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelAvatarBuilder.cs @@ -0,0 +1,1154 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEditor; +using UnityEngine; +using UnityEngine.Networking; +using VRC.SDKBase.Editor.BuildPipeline; +using VRC.SDKBase.Validation.Performance; +using VRC.SDKBase.Validation.Performance.Stats; +using Object = UnityEngine.Object; + +namespace VRC.SDKBase.Editor +{ + public class VRCSdkControlPanelAvatarBuilder : IVRCSdkControlPanelBuilder + { + protected VRCSdkControlPanel _builder; + private VRC_AvatarDescriptor[] _avatars; + private static VRC_AvatarDescriptor _selectedAvatar; + private Vector2 _avatarListScrollPos; + private Vector2 _scrollPos; + + + protected const int MAX_ACTION_TEXTURE_SIZE = 256; + + private bool showAvatarPerformanceDetails + { + get => EditorPrefs.GetBool("VRC.SDKBase_showAvatarPerformanceDetails", false); + set => EditorPrefs.SetBool("VRC.SDKBase_showAvatarPerformanceDetails", + value); //Do we ever actually set this? + } + + private static PropertyInfo _legacyBlendShapeNormalsPropertyInfo; + + private static PropertyInfo LegacyBlendShapeNormalsPropertyInfo + { + get + { + if (_legacyBlendShapeNormalsPropertyInfo != null) + { + return _legacyBlendShapeNormalsPropertyInfo; + } + + Type modelImporterType = typeof(ModelImporter); + _legacyBlendShapeNormalsPropertyInfo = modelImporterType.GetProperty( + "legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes", + BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public + ); + + return _legacyBlendShapeNormalsPropertyInfo; + } + } + + public void ShowSettingsOptions() + { + EditorGUILayout.BeginVertical(VRCSdkControlPanel.boxGuiStyle); + GUILayout.Label("Avatar Options", EditorStyles.boldLabel); + bool prevShowPerfDetails = showAvatarPerformanceDetails; + bool showPerfDetails = + EditorGUILayout.ToggleLeft("Show All Avatar Performance Details", prevShowPerfDetails); + if (showPerfDetails != prevShowPerfDetails) + { + showAvatarPerformanceDetails = showPerfDetails; + _builder.ResetIssues(); + } + + EditorGUILayout.EndVertical(); + } + + public bool IsValidBuilder(out string message) + { + FindAvatars(); + message = null; + if (_avatars != null && _avatars.Length > 0) return true; +#if VRC_SDK_VRCSDK2 + message = "A VRC_SceneDescriptor or VRC_AvatarDescriptor\nis required to build VRChat SDK Content"; +#elif VRC_SDK_VRCSDK3 + message = "A VRCSceneDescriptor or VRCAvatarDescriptor\nis required to build VRChat SDK Content"; +#endif + return false; + } + + public virtual void ShowBuilder() + { + if (_avatars.Length > 0) + { + if (!_builder.CheckedForIssues) + { + _builder.ResetIssues(); + foreach (VRC_AvatarDescriptor t in _avatars) + OnGUIAvatarCheck(t); + _builder.CheckedForIssues = true; + } + + bool drawList = true; + if (_avatars.Length == 1) + { + drawList = false; + _selectedAvatar = _avatars[0]; + } + + if (drawList) + { + EditorGUILayout.BeginVertical(GUI.skin.GetStyle("HelpBox"), + GUILayout.Width(VRCSdkControlPanel.SdkWindowWidth), + GUILayout.MaxHeight(150)); + _avatarListScrollPos = EditorGUILayout.BeginScrollView(_avatarListScrollPos, false, false); + + for (int i = 0; i < _avatars.Length; ++i) + { + VRC_AvatarDescriptor av = _avatars[i]; + EditorGUILayout.Space(); + if (_selectedAvatar == av) + { + if (GUILayout.Button(av.gameObject.name, + VRCSdkControlPanel.listButtonStyleSelected, + GUILayout.Width(VRCSdkControlPanel.SdkWindowWidth - 50))) + _selectedAvatar = null; + } + else + { + if (GUILayout.Button(av.gameObject.name, + ((i & 0x01) > 0) + ? (VRCSdkControlPanel.listButtonStyleOdd) + : (VRCSdkControlPanel.listButtonStyleEven), + GUILayout.Width(VRCSdkControlPanel.SdkWindowWidth - 50))) + _selectedAvatar = av; + } + } + + EditorGUILayout.EndScrollView(); + EditorGUILayout.EndVertical(); + } + + EditorGUILayout.BeginVertical(GUILayout.Width(VRCSdkControlPanel.SdkWindowWidth)); + _builder.OnGUIShowIssues(); + EditorGUILayout.EndVertical(); + + EditorGUILayout.Separator(); + + if (_selectedAvatar != null) + { + EditorGUILayout.BeginVertical(VRCSdkControlPanel.boxGuiStyle); + OnGUIAvatarSettings(_selectedAvatar); + EditorGUILayout.EndVertical(); + + _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos, + false, + false, + GUILayout.Width(VRCSdkControlPanel.SdkWindowWidth)); + _builder.OnGUIShowIssues(_selectedAvatar); + EditorGUILayout.EndScrollView(); + + GUILayout.FlexibleSpace(); + + OnGUIAvatar(_selectedAvatar); + } + } + else + { + EditorGUILayout.Space(); + if (UnityEditor.BuildPipeline.isBuildingPlayer) + { + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Building – Please Wait ...", + VRCSdkControlPanel.titleGuiStyle, + GUILayout.Width(VRCSdkControlPanel.SdkWindowWidth)); + } + else + { +#if VRC_SDK_VRCSDK2 + EditorGUILayout.LabelField( + "A VRC_SceneDescriptor or VRC_AvatarDescriptor\nis required to build VRChat SDK Content", + VRCSdkControlPanel.titleGuiStyle, GUILayout.Width(VRCSdkControlPanel.SdkWindowWidth)); +#elif VRC_SDK_VRCSDK3 + EditorGUILayout.LabelField( + "A VRCSceneDescriptor or VRCAvatarDescriptor\nis required to build VRChat SDK Content", + VRCSdkControlPanel.titleGuiStyle, GUILayout.Width(VRCSdkControlPanel.SdkWindowWidth)); +#else + EditorGUILayout.LabelField("A SceneDescriptor or AvatarDescriptor\nis required to build VRChat SDK Content", VRCSdkControlPanel.titleGuiStyle, GUILayout.Width(VRCSdkControlPanel.SdkWindowWidth)); +#endif + } + } + } + + public void RegisterBuilder(VRCSdkControlPanel baseBuilder) + { + _builder = baseBuilder; + } + + public void SelectAllComponents() + { + List<Object> show = new List<Object>(Selection.objects); + foreach (VRC_AvatarDescriptor a in _avatars) + show.Add(a.gameObject); + Selection.objects = show.ToArray(); + } + + private void FindAvatars() + { + List<VRC_AvatarDescriptor> allAvatars = Tools.FindSceneObjectsOfTypeAll<VRC_AvatarDescriptor>().ToList(); + // Select only the active avatars + VRC_AvatarDescriptor[] newAvatars = + allAvatars.Where(av => null != av && av.gameObject.activeInHierarchy).ToArray(); + + if (_avatars != null) + { + foreach (VRC_AvatarDescriptor a in newAvatars) + if (_avatars.Contains(a) == false) + _builder.CheckedForIssues = false; + } + + _avatars = newAvatars; + } + + public virtual void OnGUIAvatarCheck(VRC_AvatarDescriptor avatar) + { + string vrcFilePath = UnityWebRequest.UnEscapeURL(EditorPrefs.GetString("currentBuildingAssetBundlePath")); + if (!string.IsNullOrEmpty(vrcFilePath) && + ValidationHelpers.CheckIfAssetBundleFileTooLarge(ContentType.Avatar, vrcFilePath, out int fileSize)) + { + _builder.OnGUIWarning(avatar, + ValidationHelpers.GetAssetBundleOverSizeLimitMessageSDKWarning(ContentType.Avatar, fileSize), + delegate { Selection.activeObject = avatar.gameObject; }, null); + } + + AvatarPerformanceStats perfStats = new AvatarPerformanceStats(); + AvatarPerformance.CalculatePerformanceStats(avatar.Name, avatar.gameObject, perfStats); + + OnGUIPerformanceInfo(avatar, perfStats, AvatarPerformanceCategory.Overall, + GetAvatarSubSelectAction(avatar, typeof(VRC_AvatarDescriptor)), null); + OnGUIPerformanceInfo(avatar, perfStats, AvatarPerformanceCategory.PolyCount, + GetAvatarSubSelectAction(avatar, new[] {typeof(MeshRenderer), typeof(SkinnedMeshRenderer)}), null); + OnGUIPerformanceInfo(avatar, perfStats, AvatarPerformanceCategory.AABB, + GetAvatarSubSelectAction(avatar, typeof(VRC_AvatarDescriptor)), null); + + if (avatar.lipSync == VRC_AvatarDescriptor.LipSyncStyle.VisemeBlendShape && + avatar.VisemeSkinnedMesh == null) + _builder.OnGUIError(avatar, "This avatar uses Visemes but the Face Mesh is not specified.", + delegate { Selection.activeObject = avatar.gameObject; }, null); + + if (ShaderKeywordsUtility.DetectCustomShaderKeywords(avatar)) + _builder.OnGUIWarning(avatar, + "A Material on this avatar has custom shader keywords. Please consider optimizing it using the Shader Keywords Utility.", + () => { Selection.activeObject = avatar.gameObject; }, + () => + { + EditorApplication.ExecuteMenuItem("VRChat SDK/Utilities/Avatar Shader Keywords Utility"); + }); + + VerifyAvatarMipMapStreaming(avatar); + + Animator anim = avatar.GetComponent<Animator>(); + if (anim == null) + { + _builder.OnGUIWarning(avatar, + "This avatar does not contain an Animator, and will not animate in VRChat.", + delegate { Selection.activeObject = avatar.gameObject; }, null); + } + else if (anim.isHuman == false) + { + _builder.OnGUIWarning(avatar, + "This avatar is not imported as a humanoid rig and will not play VRChat's provided animation set.", + delegate { Selection.activeObject = avatar.gameObject; }, null); + } + else if (avatar.gameObject.activeInHierarchy == false) + { + _builder.OnGUIError(avatar, "Your avatar is disabled in the scene hierarchy!", + delegate { Selection.activeObject = avatar.gameObject; }, null); + } + else + { + Transform lFoot = anim.GetBoneTransform(HumanBodyBones.LeftFoot); + Transform rFoot = anim.GetBoneTransform(HumanBodyBones.RightFoot); + if ((lFoot == null) || (rFoot == null)) + _builder.OnGUIError(avatar, "Your avatar is humanoid, but its feet aren't specified!", + delegate { Selection.activeObject = avatar.gameObject; }, null); + if (lFoot != null && rFoot != null) + { + Vector3 footPos = lFoot.position - avatar.transform.position; + if (footPos.y < 0) + _builder.OnGUIWarning(avatar, + "Avatar feet are beneath the avatar's origin (the floor). That's probably not what you want.", + delegate + { + List<Object> gos = new List<Object> {rFoot.gameObject, lFoot.gameObject}; + Selection.objects = gos.ToArray(); + }, null); + } + + Transform lShoulder = anim.GetBoneTransform(HumanBodyBones.LeftUpperArm); + Transform rShoulder = anim.GetBoneTransform(HumanBodyBones.RightUpperArm); + if (lShoulder == null || rShoulder == null) + _builder.OnGUIError(avatar, "Your avatar is humanoid, but its upper arms aren't specified!", + delegate { Selection.activeObject = avatar.gameObject; }, null); + if (lShoulder != null && rShoulder != null) + { + Vector3 shoulderPosition = lShoulder.position - avatar.transform.position; + if (shoulderPosition.y < 0.2f) + _builder.OnGUIError(avatar, "This avatar is too short. The minimum is 20cm shoulder height.", + delegate { Selection.activeObject = avatar.gameObject; }, null); + else if (shoulderPosition.y < 1.0f) + _builder.OnGUIWarning(avatar, "This avatar is shorter than average.", + delegate { Selection.activeObject = avatar.gameObject; }, null); + else if (shoulderPosition.y > 5.0f) + _builder.OnGUIWarning(avatar, "This avatar is too tall. The maximum is 5m shoulder height.", + delegate { Selection.activeObject = avatar.gameObject; }, null); + else if (shoulderPosition.y > 2.5f) + _builder.OnGUIWarning(avatar, "This avatar is taller than average.", + delegate { Selection.activeObject = avatar.gameObject; }, null); + } + + if (AnalyzeIK(avatar, anim) == false) + _builder.OnGUILink(avatar, "See Avatar Rig Requirements for more information.", + VRCSdkControlPanel.AVATAR_RIG_REQUIREMENTS_URL); + } + + ValidateFeatures(avatar, anim, perfStats); + + Core.PipelineManager pm = avatar.GetComponent<Core.PipelineManager>(); + + PerformanceRating rating = perfStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.Overall); + if (_builder.NoGuiErrors()) + { + if (!anim.isHuman) + { + if (pm != null) pm.fallbackStatus = Core.PipelineManager.FallbackStatus.InvalidRig; + _builder.OnGUIInformation(avatar, "This avatar does not have a humanoid rig, so it can not be used as a custom fallback."); + } + else if (rating > PerformanceRating.Good) + { + if (pm != null) pm.fallbackStatus = Core.PipelineManager.FallbackStatus.InvalidPerformance; + _builder.OnGUIInformation(avatar, "This avatar does not have an overall rating of Good or better, so it can not be used as a custom fallback. See the link below for details on Avatar Optimization."); + } + else + { + if (pm != null) pm.fallbackStatus = Core.PipelineManager.FallbackStatus.Valid; + _builder.OnGUIInformation(avatar, "This avatar can be used as a custom fallback. This avatar must be uploaded for every supported platform to be valid for fallback selection."); + if (perfStats.animatorCount.HasValue && perfStats.animatorCount.Value > 1) + _builder.OnGUIInformation(avatar, "This avatar uses additional animators, they will be disabled when used as a fallback."); + } + + // additional messages for Poor and Very Poor Avatars +#if UNITY_ANDROID + if (rating > PerformanceRating.Poor) + _builder.OnGUIInformation(avatar, "This avatar will be blocked by default due to performance. Your fallback will be shown instead."); + else if (rating > PerformanceRating.Medium) + _builder.OnGUIInformation(avatar, "Other users may choose to block this avatar due to performance. Your fallback will be shown instead."); +#else + if (rating > PerformanceRating.Medium) + _builder.OnGUIInformation(avatar, "Other users may choose to block this avatar due to performance. Your fallback will be shown instead."); +#endif + } + else + { + // shouldn't matter because we can't hit upload button + if (pm != null) pm.fallbackStatus = Core.PipelineManager.FallbackStatus.InvalidPlatform; + } + } + + public virtual void ValidateFeatures(VRC_AvatarDescriptor avatar, Animator anim, AvatarPerformanceStats perfStats) + { + // stub, used in SDK3A for Expression Menu, etc. + } + + protected void OnGUIPerformanceInfo(VRC_AvatarDescriptor avatar, AvatarPerformanceStats perfStats, + AvatarPerformanceCategory perfCategory, Action show, Action fix) + { + PerformanceRating rating = perfStats.GetPerformanceRatingForCategory(perfCategory); + SDKPerformanceDisplay.GetSDKPerformanceInfoText(perfStats, perfCategory, out string text, + out PerformanceInfoDisplayLevel displayLevel); + + switch (displayLevel) + { + case PerformanceInfoDisplayLevel.None: + { + break; + } + case PerformanceInfoDisplayLevel.Verbose: + { + if (showAvatarPerformanceDetails) + { + _builder.OnGUIStat(avatar, text, rating, show, fix); + } + + break; + } + case PerformanceInfoDisplayLevel.Info: + { + _builder.OnGUIStat(avatar, text, rating, show, fix); + break; + } + case PerformanceInfoDisplayLevel.Warning: + { + _builder.OnGUIStat(avatar, text, rating, show, fix); + break; + } + case PerformanceInfoDisplayLevel.Error: + { + _builder.OnGUIStat(avatar, text, rating, show, fix); + _builder.OnGUIError(avatar, text, delegate { Selection.activeObject = avatar.gameObject; }, null); + break; + } + default: + { + _builder.OnGUIError(avatar, "Unknown performance display level.", + delegate { Selection.activeObject = avatar.gameObject; }, null); + break; + } + } + } + + public virtual void OnGUIAvatar(VRC_AvatarDescriptor avatar) + { + EditorGUILayout.BeginVertical(VRCSdkControlPanel.boxGuiStyle); + EditorGUILayout.BeginHorizontal(); + + EditorGUILayout.BeginVertical(GUILayout.Width(300)); + EditorGUILayout.Space(); + + GUILayout.Label("Online Publishing", VRCSdkControlPanel.infoGuiStyle); + GUILayout.Label( + "In order for other people to see your avatar in VRChat it must be built and published to our game servers.", + VRCSdkControlPanel.infoGuiStyle); + + EditorGUILayout.EndVertical(); + + EditorGUILayout.BeginVertical(GUILayout.Width(200)); + EditorGUILayout.Space(); + + GUI.enabled = _builder.NoGuiErrorsOrIssues() || + Core.APIUser.CurrentUser.developerType == Core.APIUser.DeveloperType.Internal; + if (GUILayout.Button(VRCSdkControlPanel.GetBuildAndPublishButtonString())) + { + bool buildBlocked = !VRCBuildPipelineCallbacks.OnVRCSDKBuildRequested(VRCSDKRequestedBuildType.Avatar); + if (!buildBlocked) + { + if (Core.APIUser.CurrentUser.canPublishAvatars) + { + EnvConfig.FogSettings originalFogSettings = EnvConfig.GetFogSettings(); + EnvConfig.SetFogSettings( + new EnvConfig.FogSettings(EnvConfig.FogSettings.FogStrippingMode.Custom, true, true, true)); + +#if UNITY_ANDROID + EditorPrefs.SetBool("VRC.SDKBase_StripAllShaders", true); +#else + EditorPrefs.SetBool("VRC.SDKBase_StripAllShaders", false); +#endif + +#if VRC_SDK_VRCSDK2 + VRC_SdkBuilder.shouldBuildUnityPackage = VRCSdkControlPanel.FutureProofPublishEnabled; + VRC_SdkBuilder.ExportAndUploadAvatarBlueprint(avatar.gameObject); +#endif + + EnvConfig.SetFogSettings(originalFogSettings); + + // this seems to workaround a Unity bug that is clearing the formatting of two levels of Layout + // when we call the upload functions + return; + } + else + { + VRCSdkControlPanel.ShowContentPublishPermissionsDialog(); + } + } + } + + EditorGUILayout.EndVertical(); + EditorGUILayout.Space(); + + EditorGUILayout.EndHorizontal(); + EditorGUILayout.EndVertical(); + + GUI.enabled = true; + } + + private static void OnGUIAvatarSettings(VRC_AvatarDescriptor avatar) + { + EditorGUILayout.BeginVertical(VRCSdkControlPanel.boxGuiStyle, GUILayout.Width(VRCSdkControlPanel.SdkWindowWidth)); + + string name = "Unpublished Avatar - " + avatar.gameObject.name; + if (avatar.apiAvatar != null) + name = (avatar.apiAvatar as Core.ApiAvatar)?.name; + EditorGUILayout.Space(); + EditorGUILayout.LabelField(name, VRCSdkControlPanel.titleGuiStyle); + + Core.PipelineManager pm = avatar.GetComponent<Core.PipelineManager>(); + if (pm != null && !string.IsNullOrEmpty(pm.blueprintId)) + { + if (avatar.apiAvatar == null) + { + Core.ApiAvatar av = Core.API.FromCacheOrNew<Core.ApiAvatar>(pm.blueprintId); + av.Fetch( + c => avatar.apiAvatar = c.Model as Core.ApiAvatar, + c => + { + if (c.Code == 404) + { + Core.Logger.Log( + $"Could not load avatar {pm.blueprintId} because it didn't exist.", + Core.DebugLevel.API); + Core.ApiCache.Invalidate<Core.ApiWorld>(pm.blueprintId); + } + else + Debug.LogErrorFormat("Could not load avatar {0} because {1}", pm.blueprintId, c.Error); + }); + avatar.apiAvatar = av; + } + } + + if (avatar.apiAvatar != null) + { + Core.ApiAvatar a = (avatar.apiAvatar as Core.ApiAvatar); + DrawContentInfoForAvatar(a); + VRCSdkControlPanel.DrawContentPlatformSupport(a); + } + + VRCSdkControlPanel.DrawBuildTargetSwitcher(); + EditorGUILayout.EndVertical(); + } + + private static void DrawContentInfoForAvatar(Core.ApiAvatar a) + { + VRCSdkControlPanel.DrawContentInfo(a.name, a.version.ToString(), a.description, null, a.releaseStatus, + a.tags); + } + + protected static Action GetAvatarSubSelectAction(Component avatar, Type[] types) + { + return () => + { + List<Object> gos = new List<Object>(); + foreach (Type t in types) + { + Component[] components = avatar.GetComponentsInChildren(t, true); + foreach (Component c in components) + gos.Add(c.gameObject); + } + + Selection.objects = gos.Count > 0 ? gos.ToArray() : new Object[] {avatar.gameObject}; + }; + } + + protected static Action GetAvatarSubSelectAction(Component avatar, Type type) + { + List<Type> t = new List<Type> {type}; + return GetAvatarSubSelectAction(avatar, t.ToArray()); + } + + private void VerifyAvatarMipMapStreaming(Component avatar) + { + List<Object> badTextures = new List<Object>(); + foreach (Renderer r in avatar.GetComponentsInChildren<Renderer>(true)) + { + foreach (Material m in r.sharedMaterials) + { + if (!m) + continue; + int[] texIDs = m.GetTexturePropertyNameIDs(); + if (texIDs == null) + continue; + foreach (int i in texIDs) + { + Texture t = m.GetTexture(i); + if (!t) + continue; + string path = AssetDatabase.GetAssetPath(t); + if (string.IsNullOrEmpty(path)) + continue; + TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter; + if (importer != null && importer.mipmapEnabled && !importer.streamingMipmaps) + badTextures.Add(importer); + } + } + } + + if (badTextures.Count == 0) + return; + + _builder.OnGUIError(avatar, "This avatar has mipmapped textures without 'Streaming Mip Maps' enabled.", + () => { Selection.objects = badTextures.ToArray(); }, + () => + { + List<string> paths = new List<string>(); + foreach (Object o in badTextures) + { + TextureImporter t = (TextureImporter) o; + Undo.RecordObject(t, "Set Mip Map Streaming"); + t.streamingMipmaps = true; + t.streamingMipmapsPriority = 0; + EditorUtility.SetDirty(t); + paths.Add(t.assetPath); + } + + AssetDatabase.ForceReserializeAssets(paths); + AssetDatabase.Refresh(); + }); + } + + private bool AnalyzeIK(Object ad, Animator anim) + { + bool hasHead; + bool hasFeet; + bool hasHands; +#if VRC_SDK_VRCSDK2 + bool hasThreeFingers; +#endif + bool correctSpineHierarchy; + bool correctLeftArmHierarchy; + bool correctRightArmHierarchy; + bool correctLeftLegHierarchy; + bool correctRightLegHierarchy; + + bool status = true; + + Transform head = anim.GetBoneTransform(HumanBodyBones.Head); + Transform lFoot = anim.GetBoneTransform(HumanBodyBones.LeftFoot); + Transform rFoot = anim.GetBoneTransform(HumanBodyBones.RightFoot); + Transform lHand = anim.GetBoneTransform(HumanBodyBones.LeftHand); + Transform rHand = anim.GetBoneTransform(HumanBodyBones.RightHand); + + hasHead = null != head; + hasFeet = (null != lFoot && null != rFoot); + hasHands = (null != lHand && null != rHand); + + if (!hasHead || !hasFeet || !hasHands) + { + _builder.OnGUIError(ad, "Humanoid avatar must have head, hands and feet bones mapped.", + delegate { Selection.activeObject = anim.gameObject; }, null); + return false; + } + + Transform lThumb = anim.GetBoneTransform(HumanBodyBones.LeftThumbProximal); + Transform lIndex = anim.GetBoneTransform(HumanBodyBones.LeftIndexProximal); + Transform lMiddle = anim.GetBoneTransform(HumanBodyBones.LeftMiddleProximal); + Transform rThumb = anim.GetBoneTransform(HumanBodyBones.RightThumbProximal); + Transform rIndex = anim.GetBoneTransform(HumanBodyBones.RightIndexProximal); + Transform rMiddle = anim.GetBoneTransform(HumanBodyBones.RightMiddleProximal); + +#if VRC_SDK_VRCSDK2 + // Finger test, only for v2 + hasThreeFingers = null != lThumb && null != lIndex && null != lMiddle && null != rThumb && null != rIndex && + null != rMiddle; + + if (!hasThreeFingers) + { + // although its only a warning, we return here because the rest + // of the analysis is for VR IK + _builder.OnGUIWarning(ad, + "Thumb, Index, and Middle finger bones are not mapped, Full-Body IK will be disabled.", + delegate { Selection.activeObject = anim.gameObject; }, null); + status = false; + } +#endif + + Transform pelvis = anim.GetBoneTransform(HumanBodyBones.Hips); + Transform chest = anim.GetBoneTransform(HumanBodyBones.Chest); + Transform upperChest = anim.GetBoneTransform(HumanBodyBones.UpperChest); + Transform torso = anim.GetBoneTransform(HumanBodyBones.Spine); + + Transform neck = anim.GetBoneTransform(HumanBodyBones.Neck); + Transform lClav = anim.GetBoneTransform(HumanBodyBones.LeftShoulder); + Transform rClav = anim.GetBoneTransform(HumanBodyBones.RightShoulder); + + + if (null == neck || null == lClav || null == rClav || null == pelvis || null == torso || null == chest) + { + string missingElements = + ((null == neck) ? "Neck, " : "") + + (((null == lClav) || (null == rClav)) ? "Shoulders, " : "") + + ((null == pelvis) ? "Pelvis, " : "") + + ((null == torso) ? "Spine, " : "") + + ((null == chest) ? "Chest, " : ""); + missingElements = missingElements.Remove(missingElements.LastIndexOf(',')) + "."; + _builder.OnGUIError(ad, "Spine hierarchy missing elements, please map: " + missingElements, + delegate { Selection.activeObject = anim.gameObject; }, null); + return false; + } + + if (null != upperChest) + correctSpineHierarchy = + lClav.parent == upperChest && rClav.parent == upperChest && neck.parent == upperChest; + else + correctSpineHierarchy = lClav.parent == chest && rClav.parent == chest && neck.parent == chest; + + if (!correctSpineHierarchy) + { + _builder.OnGUIError(ad, + "Spine hierarchy incorrect. Make sure that the parent of both Shoulders and the Neck is the Chest (or UpperChest if set).", + delegate + { + List<Object> gos = new List<Object> + { + lClav.gameObject, + rClav.gameObject, + neck.gameObject, + null != upperChest ? upperChest.gameObject : chest.gameObject + }; + Selection.objects = gos.ToArray(); + }, null); + return false; + } + + Transform lShoulder = anim.GetBoneTransform(HumanBodyBones.LeftUpperArm); + Transform lElbow = anim.GetBoneTransform(HumanBodyBones.LeftLowerArm); + Transform rShoulder = anim.GetBoneTransform(HumanBodyBones.RightUpperArm); + Transform rElbow = anim.GetBoneTransform(HumanBodyBones.RightLowerArm); + + correctLeftArmHierarchy = lShoulder && lElbow && lShoulder.GetChild(0) == lElbow && lHand && + lElbow.GetChild(0) == lHand; + correctRightArmHierarchy = rShoulder && rElbow && rShoulder.GetChild(0) == rElbow && rHand && + rElbow.GetChild(0) == rHand; + + if (!(correctLeftArmHierarchy && correctRightArmHierarchy)) + { + _builder.OnGUIWarning(ad, + "LowerArm is not first child of UpperArm or Hand is not first child of LowerArm: you may have problems with Forearm rotations.", + delegate + { + List<Object> gos = new List<Object>(); + if (!correctLeftArmHierarchy && lShoulder) + gos.Add(lShoulder.gameObject); + if (!correctRightArmHierarchy && rShoulder) + gos.Add(rShoulder.gameObject); + if (gos.Count > 0) + Selection.objects = gos.ToArray(); + else + Selection.activeObject = anim.gameObject; + }, null); + status = false; + } + + Transform lHip = anim.GetBoneTransform(HumanBodyBones.LeftUpperLeg); + Transform lKnee = anim.GetBoneTransform(HumanBodyBones.LeftLowerLeg); + Transform rHip = anim.GetBoneTransform(HumanBodyBones.RightUpperLeg); + Transform rKnee = anim.GetBoneTransform(HumanBodyBones.RightLowerLeg); + + correctLeftLegHierarchy = lHip && lKnee && lHip.GetChild(0) == lKnee && lKnee.GetChild(0) == lFoot; + correctRightLegHierarchy = rHip && rKnee && rHip.GetChild(0) == rKnee && rKnee.GetChild(0) == rFoot; + + if (!(correctLeftLegHierarchy && correctRightLegHierarchy)) + { + _builder.OnGUIWarning(ad, + "LowerLeg is not first child of UpperLeg or Foot is not first child of LowerLeg: you may have problems with Shin rotations.", + delegate + { + List<Object> gos = new List<Object>(); + if (!correctLeftLegHierarchy && lHip) + gos.Add(lHip.gameObject); + if (!correctRightLegHierarchy && rHip) + gos.Add(rHip.gameObject); + if (gos.Count > 0) + Selection.objects = gos.ToArray(); + else + Selection.activeObject = anim.gameObject; + }, null); + status = false; + } + + if (!(IsAncestor(pelvis, rFoot) && IsAncestor(pelvis, lFoot) && IsAncestor(pelvis, lHand) && + IsAncestor(pelvis, rHand))) + { + _builder.OnGUIWarning(ad, + "This avatar has a split hierarchy (Hips bone is not the ancestor of all humanoid bones). IK may not work correctly.", + delegate + { + List<Object> gos = new List<Object> {pelvis.gameObject}; + if (!IsAncestor(pelvis, rFoot)) + gos.Add(rFoot.gameObject); + if (!IsAncestor(pelvis, lFoot)) + gos.Add(lFoot.gameObject); + if (!IsAncestor(pelvis, lHand)) + gos.Add(lHand.gameObject); + if (!IsAncestor(pelvis, rHand)) + gos.Add(rHand.gameObject); + Selection.objects = gos.ToArray(); + }, null); + status = false; + } + + // if thigh bone rotations diverge from 180 from hip bone rotations, full-body tracking/ik does not work well + if (!lHip || !rHip) return status; + { + Vector3 hipLocalUp = pelvis.InverseTransformVector(Vector3.up); + Vector3 legLDir = lHip.TransformVector(hipLocalUp); + Vector3 legRDir = rHip.TransformVector(hipLocalUp); + float angL = Vector3.Angle(Vector3.up, legLDir); + float angR = Vector3.Angle(Vector3.up, legRDir); + if (!(angL < 175f) && !(angR < 175f)) return status; + string angle = $"{Mathf.Min(angL, angR):F1}"; + _builder.OnGUIWarning(ad, + $"The angle between pelvis and thigh bones should be close to 180 degrees (this avatar's angle is {angle}). Your avatar may not work well with full-body IK and Tracking.", + delegate + { + List<Object> gos = new List<Object>(); + if (angL < 175f) + gos.Add(rFoot.gameObject); + if (angR < 175f) + gos.Add(lFoot.gameObject); + Selection.objects = gos.ToArray(); + }, null); + status = false; + } + + return status; + } + + private static bool IsAncestor(Object ancestor, Transform child) + { + bool found = false; + Transform thisParent = child.parent; + while (thisParent != null) + { + if (thisParent == ancestor) + { + found = true; + break; + } + + thisParent = thisParent.parent; + } + + return found; + } + + protected void CheckAvatarMeshesForLegacyBlendShapesSetting(Component avatar) + { + if (LegacyBlendShapeNormalsPropertyInfo == null) + { + Debug.LogError( + "Could not check for legacy blend shape normals because 'legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes' was not found."); + return; + } + + // Get all of the meshes used by skinned mesh renderers. + HashSet<Mesh> avatarMeshes = GetAllMeshesInGameObjectHierarchy(avatar.gameObject); + HashSet<Mesh> incorrectlyConfiguredMeshes = + ScanMeshesForIncorrectBlendShapeNormalsSetting(avatarMeshes); + if (incorrectlyConfiguredMeshes.Count > 0) + { + _builder.OnGUIError( + avatar, + "This avatar contains skinned meshes that were imported with Blendshape Normals set to 'Calculate' but aren't using 'Legacy Blendshape Normals'. This will significantly increase the size of the uploaded avatar. This must be fixed in the mesh import settings before uploading.", + null, + () => { EnableLegacyBlendShapeNormals(incorrectlyConfiguredMeshes); }); + } + } + + private static HashSet<Mesh> ScanMeshesForIncorrectBlendShapeNormalsSetting(IEnumerable<Mesh> avatarMeshes) + { + HashSet<Mesh> incorrectlyConfiguredMeshes = new HashSet<Mesh>(); + foreach (Mesh avatarMesh in avatarMeshes) + { + // Can't get ModelImporter if the model isn't an asset. + if (!AssetDatabase.Contains(avatarMesh)) + { + continue; + } + + string meshAssetPath = AssetDatabase.GetAssetPath(avatarMesh); + if (string.IsNullOrEmpty(meshAssetPath)) + { + continue; + } + + ModelImporter avatarImporter = AssetImporter.GetAtPath(meshAssetPath) as ModelImporter; + if (avatarImporter == null) + { + continue; + } + + if (avatarImporter.importBlendShapeNormals != ModelImporterNormals.Calculate) + { + continue; + } + + bool useLegacyBlendShapeNormals = (bool) LegacyBlendShapeNormalsPropertyInfo.GetValue(avatarImporter); + if (useLegacyBlendShapeNormals) + { + continue; + } + + if (!incorrectlyConfiguredMeshes.Contains(avatarMesh)) + { + incorrectlyConfiguredMeshes.Add(avatarMesh); + } + } + + return incorrectlyConfiguredMeshes; + } + + private static void EnableLegacyBlendShapeNormals(IEnumerable<Mesh> meshesToFix) + { + HashSet<string> meshAssetPaths = new HashSet<string>(); + foreach (Mesh meshToFix in meshesToFix) + { + // Can't get ModelImporter if the model isn't an asset. + if (!AssetDatabase.Contains(meshToFix)) + { + continue; + } + + string meshAssetPath = AssetDatabase.GetAssetPath(meshToFix); + if (string.IsNullOrEmpty(meshAssetPath)) + { + continue; + } + + if (meshAssetPaths.Contains(meshAssetPath)) + { + continue; + } + + meshAssetPaths.Add(meshAssetPath); + } + + foreach (string meshAssetPath in meshAssetPaths) + { + ModelImporter avatarImporter = AssetImporter.GetAtPath(meshAssetPath) as ModelImporter; + if (avatarImporter == null) + { + continue; + } + + if (avatarImporter.importBlendShapeNormals != ModelImporterNormals.Calculate) + { + continue; + } + + LegacyBlendShapeNormalsPropertyInfo.SetValue(avatarImporter, true); + avatarImporter.SaveAndReimport(); + } + } + + protected void CheckAvatarMeshesForMeshReadWriteSetting(Component avatar) + { + // Get all of the meshes used by skinned mesh renderers. + HashSet<Mesh> avatarMeshes = GetAllMeshesInGameObjectHierarchy(avatar.gameObject); + HashSet<Mesh> incorrectlyConfiguredMeshes = + ScanMeshesForDisabledMeshReadWriteSetting(avatarMeshes); + if (incorrectlyConfiguredMeshes.Count > 0) + { + _builder.OnGUIError( + avatar, + "This avatar contains meshes that were imported with Read/Write disabled. This must be fixed in the mesh import settings before uploading.", + null, + () => { EnableMeshReadWrite(incorrectlyConfiguredMeshes); }); + } + } + + private static HashSet<Mesh> ScanMeshesForDisabledMeshReadWriteSetting(IEnumerable<Mesh> avatarMeshes) + { + HashSet<Mesh> incorrectlyConfiguredMeshes = new HashSet<Mesh>(); + foreach (Mesh avatarMesh in avatarMeshes) + { + // Can't get ModelImporter if the model isn't an asset. + if (!AssetDatabase.Contains(avatarMesh)) + { + continue; + } + + string meshAssetPath = AssetDatabase.GetAssetPath(avatarMesh); + if (string.IsNullOrEmpty(meshAssetPath)) + { + continue; + } + + ModelImporter avatarImporter = AssetImporter.GetAtPath(meshAssetPath) as ModelImporter; + if (avatarImporter == null) + { + continue; + } + + if (avatarImporter.isReadable) + { + continue; + } + + if (!incorrectlyConfiguredMeshes.Contains(avatarMesh)) + { + incorrectlyConfiguredMeshes.Add(avatarMesh); + } + } + + return incorrectlyConfiguredMeshes; + } + + private static void EnableMeshReadWrite(IEnumerable<Mesh> meshesToFix) + { + HashSet<string> meshAssetPaths = new HashSet<string>(); + foreach (Mesh meshToFix in meshesToFix) + { + // Can't get ModelImporter if the model isn't an asset. + if (!AssetDatabase.Contains(meshToFix)) + { + continue; + } + + string meshAssetPath = AssetDatabase.GetAssetPath(meshToFix); + if (string.IsNullOrEmpty(meshAssetPath)) + { + continue; + } + + if (meshAssetPaths.Contains(meshAssetPath)) + { + continue; + } + + meshAssetPaths.Add(meshAssetPath); + } + + foreach (string meshAssetPath in meshAssetPaths) + { + ModelImporter avatarImporter = AssetImporter.GetAtPath(meshAssetPath) as ModelImporter; + if (avatarImporter == null) + { + continue; + } + + if (avatarImporter.isReadable) + { + continue; + } + + avatarImporter.isReadable = true; + avatarImporter.SaveAndReimport(); + } + } + + private static HashSet<Mesh> GetAllMeshesInGameObjectHierarchy(GameObject avatar) + { + HashSet<Mesh> avatarMeshes = new HashSet<Mesh>(); + foreach (SkinnedMeshRenderer avatarSkinnedMeshRenderer in avatar + .GetComponentsInChildren<SkinnedMeshRenderer>(true)) + { + if (avatarSkinnedMeshRenderer == null) + { + continue; + } + + Mesh skinnedMesh = avatarSkinnedMeshRenderer.sharedMesh; + if (skinnedMesh == null) + { + continue; + } + + if (avatarMeshes.Contains(skinnedMesh)) + { + continue; + } + + avatarMeshes.Add(skinnedMesh); + } + + foreach (MeshFilter avatarMeshFilter in avatar.GetComponentsInChildren<MeshFilter>(true)) + { + if (avatarMeshFilter == null) + { + continue; + } + + Mesh skinnedMesh = avatarMeshFilter.sharedMesh; + if (skinnedMesh == null) + { + continue; + } + + if (avatarMeshes.Contains(skinnedMesh)) + { + continue; + } + + avatarMeshes.Add(skinnedMesh); + } + + foreach (ParticleSystemRenderer avatarParticleSystemRenderer in avatar + .GetComponentsInChildren<ParticleSystemRenderer>(true)) + { + if (avatarParticleSystemRenderer == null) + { + continue; + } + + Mesh[] avatarParticleSystemRendererMeshes = new Mesh[avatarParticleSystemRenderer.meshCount]; + avatarParticleSystemRenderer.GetMeshes(avatarParticleSystemRendererMeshes); + foreach (Mesh avatarParticleSystemRendererMesh in avatarParticleSystemRendererMeshes) + { + if (avatarParticleSystemRendererMesh == null) + { + continue; + } + + if (avatarMeshes.Contains(avatarParticleSystemRendererMesh)) + { + continue; + } + + avatarMeshes.Add(avatarParticleSystemRendererMesh); + } + } + + return avatarMeshes; + } + + protected void OpenAnimatorControllerWindow(object animatorController) + { + Assembly asm = Assembly.Load("UnityEditor.Graphs"); + Module editorGraphModule = asm.GetModule("UnityEditor.Graphs.dll"); + Type animatorWindowType = editorGraphModule.GetType("UnityEditor.Graphs.AnimatorControllerTool"); + EditorWindow animatorWindow = EditorWindow.GetWindow(animatorWindowType, false, "Animator", false); + PropertyInfo propInfo = animatorWindowType.GetProperty("animatorController"); + if (propInfo != null) propInfo.SetValue(animatorWindow, animatorController, null); + } + + protected static void ShowRestrictedComponents(IEnumerable<Component> componentsToRemove) + { + List<Object> gos = new List<Object>(); + foreach (Component c in componentsToRemove) + gos.Add(c.gameObject); + Selection.objects = gos.ToArray(); + } + + protected static void FixRestrictedComponents(IEnumerable<Component> componentsToRemove) + { + if (!(componentsToRemove is List<Component> list)) return; + for (int v = list.Count - 1; v > -1; v--) + { + Object.DestroyImmediate(list[v]); + } + } + + public static void SelectAvatar(VRC_AvatarDescriptor avatar) + { + if (VRCSdkControlPanel.window != null) + _selectedAvatar = avatar; + } + + + List<Transform> FindBonesBetween(Transform top, Transform bottom) + { + List<Transform> list = new List<Transform>(); + if (top == null || bottom == null) return list; + Transform bt = top.parent; + while (bt != bottom && bt != null) + { + list.Add(bt); + bt = bt.parent; + } + + return list; + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelAvatarBuilder.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelAvatarBuilder.cs.meta new file mode 100644 index 00000000..2dc1efd5 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelAvatarBuilder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d90918c7fdc97d04f918868742746f67 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelBuilder.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelBuilder.cs new file mode 100644 index 00000000..68dcc421 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelBuilder.cs @@ -0,0 +1,655 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEngine; +using UnityEditor; +using UnityEditor.SceneManagement; +using VRC.SDKBase.Validation.Performance; +using Object = UnityEngine.Object; +using VRC.SDKBase.Editor; + +public partial class VRCSdkControlPanel : EditorWindow +{ + public static System.Action _EnableSpatialization = null; // assigned in AutoAddONSPAudioSourceComponents + + public const string AVATAR_OPTIMIZATION_TIPS_URL = "https://docs.vrchat.com/docs/avatar-optimizing-tips"; + public const string AVATAR_RIG_REQUIREMENTS_URL = "https://docs.vrchat.com/docs/rig-requirements"; + + const string kCantPublishContent = "Before you can upload avatars or worlds, you will need to spend some time in VRChat."; + const string kCantPublishAvatars = "Before you can upload avatars, you will need to spend some time in VRChat."; + const string kCantPublishWorlds = "Before you can upload worlds, you will need to spend some time in VRChat."; + private const string FIX_ISSUES_TO_BUILD_OR_TEST_WARNING_STRING = "You must address the above issues before you can build or test this content!"; + + static Texture _perfIcon_Excellent; + static Texture _perfIcon_Good; + static Texture _perfIcon_Medium; + static Texture _perfIcon_Poor; + static Texture _perfIcon_VeryPoor; + static Texture _bannerImage; + + public void ResetIssues() + { + GUIErrors.Clear(); + GUIInfos.Clear(); + GUIWarnings.Clear(); + GUILinks.Clear(); + GUIStats.Clear(); + CheckedForIssues = false; + } + + public bool CheckedForIssues { get; set; } = false; + + class Issue + { + public string issueText; + public System.Action showThisIssue; + public System.Action fixThisIssue; + public PerformanceRating performanceRating; + + public Issue(string text, System.Action show, System.Action fix, PerformanceRating rating = PerformanceRating.None) + { + issueText = text; + showThisIssue = show; + fixThisIssue = fix; + performanceRating = rating; + } + + public class Equality : IEqualityComparer<Issue>, IComparer<Issue> + { + public bool Equals(Issue b1, Issue b2) + { + return (b1.issueText == b2.issueText); + } + public int Compare(Issue b1, Issue b2) + { + return string.Compare(b1.issueText, b2.issueText); + } + public int GetHashCode(Issue bx) + { + return bx.issueText.GetHashCode(); + } + } + } + + Dictionary<Object, List<Issue>> GUIErrors = new Dictionary<Object, List<Issue>>(); + Dictionary<Object, List<Issue>> GUIWarnings = new Dictionary<Object, List<Issue>>(); + Dictionary<Object, List<Issue>> GUIInfos = new Dictionary<Object, List<Issue>>(); + Dictionary<Object, List<Issue>> GUILinks = new Dictionary<Object, List<Issue>>(); + Dictionary<Object, List<Issue>> GUIStats = new Dictionary<Object, List<Issue>>(); + + public bool NoGuiErrors() + { + return GUIErrors.Count == 0; + } + + public bool NoGuiErrorsOrIssues() + { + return GUIErrors.Count == 0 && CheckedForIssues; + } + + void AddToReport(Dictionary<Object, List<Issue>> report, Object subject, string output, System.Action show, System.Action fix) + { + if (subject == null) + subject = this; + if (!report.ContainsKey(subject)) + report.Add(subject, new List<Issue>()); + + var issue = new Issue(output, show, fix); + if (!report[subject].Contains(issue, new Issue.Equality())) + { + report[subject].Add(issue); + report[subject].Sort(new Issue.Equality()); + } + } + + void BuilderAssemblyReload() + { + ResetIssues(); + } + + public void OnGUIError(Object subject, string output, System.Action show, System.Action fix) + { + AddToReport(GUIErrors, subject, output, show, fix); + } + + public void OnGUIWarning(Object subject, string output, System.Action show, System.Action fix) + { + AddToReport(GUIWarnings, subject, output, show, fix); + } + + public void OnGUIInformation(Object subject, string output) + { + AddToReport(GUIInfos, subject, output, null, null); + } + + public void OnGUILink(Object subject, string output, string link) + { + AddToReport(GUILinks, subject, output + "\n" + link, null, null); + } + + public void OnGUIStat(Object subject, string output, PerformanceRating rating, System.Action show, System.Action fix) + { + if (subject == null) + subject = this; + if (!GUIStats.ContainsKey(subject)) + GUIStats.Add(subject, new List<Issue>()); + GUIStats[subject].Add(new Issue(output, show, fix, rating)); + } + + public int triggerLineMode + { + get { return EditorPrefs.GetInt("VRC.SDKBase_triggerLineMode", 0); } + set { EditorPrefs.SetInt("VRC.SDKBase_triggerLineMode", value); } + } + + private void ShowSettingsOptionsForBuilders() + { + if (_sdkBuilders == null) + { + PopulateSdkBuilders(); + } + for (int i = 0; i < _sdkBuilders.Length; i++) + { + IVRCSdkControlPanelBuilder builder = _sdkBuilders[i]; + builder.ShowSettingsOptions(); + if (i < _sdkBuilders.Length - 1) + { + EditorGUILayout.Separator(); + } + } + } + + private IVRCSdkControlPanelBuilder[] _sdkBuilders; + + private static List<Type> GetSdkBuilderTypesFromAttribute() + { + Type sdkBuilderInterfaceType = typeof(IVRCSdkControlPanelBuilder); + Type sdkBuilderAttributeType = typeof(VRCSdkControlPanelBuilderAttribute); + + List<Type> moduleTypesFromAttribute = new List<Type>(); + foreach(Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) + { + VRCSdkControlPanelBuilderAttribute[] sdkBuilderAttributes; + try + { + sdkBuilderAttributes = (VRCSdkControlPanelBuilderAttribute[])assembly.GetCustomAttributes(sdkBuilderAttributeType, true); + } + catch + { + sdkBuilderAttributes = new VRCSdkControlPanelBuilderAttribute[0]; + } + + foreach(VRCSdkControlPanelBuilderAttribute udonWrapperModuleAttribute in sdkBuilderAttributes) + { + if(udonWrapperModuleAttribute == null) + { + continue; + } + + if(!sdkBuilderInterfaceType.IsAssignableFrom(udonWrapperModuleAttribute.Type)) + { + continue; + } + + moduleTypesFromAttribute.Add(udonWrapperModuleAttribute.Type); + } + } + + return moduleTypesFromAttribute; + } + + private void PopulateSdkBuilders() + { + if (_sdkBuilders != null) + { + return; + } + List<IVRCSdkControlPanelBuilder> builders = new List<IVRCSdkControlPanelBuilder>(); + foreach (Type type in GetSdkBuilderTypesFromAttribute()) + { + IVRCSdkControlPanelBuilder builder = (IVRCSdkControlPanelBuilder)Activator.CreateInstance(type); + builder.RegisterBuilder(this); + builders.Add(builder); + } + _sdkBuilders = builders.ToArray(); + } + + void ShowBuilders() + { + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.BeginVertical(); + + if (VRC.Core.ConfigManager.RemoteConfig.IsInitialized()) + { + string sdkUnityVersion = VRC.Core.ConfigManager.RemoteConfig.GetString("sdkUnityVersion"); + if (Application.unityVersion != sdkUnityVersion) + { + OnGUIWarning(null, "You are not using the recommended Unity version for the VRChat SDK. Content built with this version may not work correctly. Please use Unity " + sdkUnityVersion, + null, + () => { Application.OpenURL("https://unity3d.com/get-unity/download/archive"); } + ); + } + } + + if (VRCSdk3Analysis.IsSdkDllActive(VRCSdk3Analysis.SdkVersion.VRCSDK2) && VRCSdk3Analysis.IsSdkDllActive(VRCSdk3Analysis.SdkVersion.VRCSDK3)) + { + List<Component> sdk2Components = VRCSdk3Analysis.GetSDKInScene(VRCSdk3Analysis.SdkVersion.VRCSDK2); + List<Component> sdk3Components = VRCSdk3Analysis.GetSDKInScene(VRCSdk3Analysis.SdkVersion.VRCSDK3); + if (sdk2Components.Count > 0 && sdk3Components.Count > 0) + { + OnGUIError(null, + "This scene contains components from the VRChat SDK version 2 and version 3. Version two elements will have to be replaced with their version 3 counterparts to build with SDK3 and UDON.", + () => { Selection.objects = sdk2Components.ToArray(); }, + null + ); + } + } + + if (Lightmapping.giWorkflowMode == Lightmapping.GIWorkflowMode.Iterative) + { + OnGUIWarning(null, + "Automatic lightmap generation is enabled, which may stall the Unity build process. Before building and uploading, consider turning off 'Auto Generate' at the bottom of the Lighting Window.", + () => + { + EditorWindow lightingWindow = GetLightingWindow(); + if (lightingWindow) + { + lightingWindow.Show(); + lightingWindow.Focus(); + } + }, + () => + { + Lightmapping.giWorkflowMode = Lightmapping.GIWorkflowMode.OnDemand; + EditorWindow lightingWindow = GetLightingWindow(); + if (!lightingWindow) return; + lightingWindow.Repaint(); + Focus(); + } + ); + } + + PopulateSdkBuilders(); + IVRCSdkControlPanelBuilder selectedBuilder = null; + string errorMessage = null; + foreach (IVRCSdkControlPanelBuilder sdkBuilder in _sdkBuilders) + { + if (!sdkBuilder.IsValidBuilder(out string message)) + { + if (selectedBuilder == null) + { + errorMessage = message; + } + } + else + { + if (selectedBuilder == null) + { + selectedBuilder = sdkBuilder; + errorMessage = null; + } + else + { + errorMessage = + "A Unity scene cannot contain a VRChat Scene Descriptor and also contain VRChat Avatar Descriptors"; + } + } + } + if (selectedBuilder == null) + { + string message = ""; +#if VRC_SDK_VRCSDK2 + message = "A VRC_SceneDescriptor or VRC_AvatarDescriptor\nis required to build VRChat SDK Content"; +#elif UDON + message = "A VRCSceneDescriptor is required to build a World"; +#elif VRC_SDK_VRCSDK3 + message = "A VRCAvatarDescriptor is required to build an Avatar"; +#else + message = "The SDK did not load properly. Try this - In the Project window, navigate to Assets/VRCSDK/Plugins. Select all the DLLs, then right click and choose 'Reimport'"; +#endif + EditorGUILayout.LabelField(message, titleGuiStyle, GUILayout.Width(SdkWindowWidth)); + } + else if (errorMessage != null) + { + OnGUIError(null, + errorMessage, + () => { + foreach (IVRCSdkControlPanelBuilder builder in _sdkBuilders) + { + builder.SelectAllComponents(); + } }, + null + ); + OnGUIShowIssues(); + } + else + { + selectedBuilder.ShowBuilder(); + } + + if (Event.current.type == EventType.Used) return; + GUILayout.EndVertical(); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + } + + public bool showLayerHelp = false; + + bool ShouldShowLightmapWarning + { + get + { + const string GraphicsSettingsAssetPath = "ProjectSettings/GraphicsSettings.asset"; + SerializedObject graphicsManager = new SerializedObject(UnityEditor.AssetDatabase.LoadAllAssetsAtPath(GraphicsSettingsAssetPath)[0]); + SerializedProperty lightmapStripping = graphicsManager.FindProperty("m_LightmapStripping"); + return lightmapStripping.enumValueIndex == 0; + } + } + + bool ShouldShowFogWarning + { + get + { + const string GraphicsSettingsAssetPath = "ProjectSettings/GraphicsSettings.asset"; + SerializedObject graphicsManager = new SerializedObject(UnityEditor.AssetDatabase.LoadAllAssetsAtPath(GraphicsSettingsAssetPath)[0]); + SerializedProperty lightmapStripping = graphicsManager.FindProperty("m_FogStripping"); + return lightmapStripping.enumValueIndex == 0; + } + } + + void DrawIssueBox(MessageType msgType, Texture icon, string message, System.Action show, System.Action fix) + { + bool haveButtons = ((show != null) || (fix != null)); + + GUIStyle style = new GUIStyle("HelpBox"); + style.fixedWidth = (haveButtons ? (SdkWindowWidth - 90) : SdkWindowWidth); + float minHeight = 40; + + try + { + EditorGUILayout.BeginHorizontal(); + if (icon != null) + { + GUIContent c = new GUIContent(message, icon); + float height = style.CalcHeight(c, style.fixedWidth); + GUILayout.Box(c, style, GUILayout.MinHeight(Mathf.Max(minHeight, height))); + } + else + { + GUIContent c = new GUIContent(message); + float height = style.CalcHeight(c, style.fixedWidth); + Rect rt = GUILayoutUtility.GetRect(c, style, GUILayout.MinHeight(Mathf.Max(minHeight, height))); + EditorGUI.HelpBox(rt, message, msgType); // note: EditorGUILayout resulted in uneven button layout in this case + } + + if (haveButtons) + { + EditorGUILayout.BeginVertical(); + float buttonHeight = ((show == null || fix == null) ? minHeight : (minHeight * 0.5f)); + if ((show != null) && GUILayout.Button("Select", GUILayout.Height(buttonHeight))) + show(); + if ((fix != null) && GUILayout.Button("Auto Fix", GUILayout.Height(buttonHeight))) + { + fix(); + EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); + CheckedForIssues = false; + Repaint(); + } + EditorGUILayout.EndVertical(); + } + + EditorGUILayout.EndHorizontal(); + } + catch + { + // mutes 'ArgumentException: Getting control 0's position in a group with only 0 controls when doing repaint' + } + } + + public void OnGuiFixIssuesToBuildOrTest() + { + GUIStyle s = new GUIStyle(EditorStyles.label) { alignment = TextAnchor.MiddleCenter }; + EditorGUILayout.Space(); + GUILayout.BeginVertical(boxGuiStyle, GUILayout.Height(WARNING_ICON_SIZE), GUILayout.Width(SdkWindowWidth)); + GUILayout.FlexibleSpace(); + EditorGUILayout.BeginHorizontal(); + var textDimensions = s.CalcSize(new GUIContent(FIX_ISSUES_TO_BUILD_OR_TEST_WARNING_STRING)); + GUILayout.Label(new GUIContent(warningIconGraphic), GUILayout.Width(WARNING_ICON_SIZE), GUILayout.Height(WARNING_ICON_SIZE)); + EditorGUILayout.LabelField(FIX_ISSUES_TO_BUILD_OR_TEST_WARNING_STRING, s, GUILayout.Width(textDimensions.x), GUILayout.Height(WARNING_ICON_SIZE)); + EditorGUILayout.EndHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.EndVertical(); + } + + public void OnGUIShowIssues(Object subject = null) + { + if (subject == null) + subject = this; + + EditorGUI.BeginChangeCheck(); + + GUIStyle style = GUI.skin.GetStyle("HelpBox"); + + if (GUIErrors.ContainsKey(subject)) + foreach (Issue error in GUIErrors[subject].Where(s => !string.IsNullOrEmpty(s.issueText))) + DrawIssueBox(MessageType.Error, null, error.issueText, error.showThisIssue, error.fixThisIssue); + if (GUIWarnings.ContainsKey(subject)) + foreach (Issue error in GUIWarnings[subject].Where(s => !string.IsNullOrEmpty(s.issueText))) + DrawIssueBox(MessageType.Warning, null, error.issueText, error.showThisIssue, error.fixThisIssue); + + if (GUIStats.ContainsKey(subject)) + { + foreach (var kvp in GUIStats[subject].Where(k => k.performanceRating == PerformanceRating.VeryPoor)) + DrawIssueBox(MessageType.Warning, GetPerformanceIconForRating(kvp.performanceRating), kvp.issueText, kvp.showThisIssue, kvp.fixThisIssue); + + foreach (var kvp in GUIStats[subject].Where(k => k.performanceRating == PerformanceRating.Poor)) + DrawIssueBox(MessageType.Warning, GetPerformanceIconForRating(kvp.performanceRating), kvp.issueText, kvp.showThisIssue, kvp.fixThisIssue); + + foreach (var kvp in GUIStats[subject].Where(k => k.performanceRating == PerformanceRating.Medium)) + DrawIssueBox(MessageType.Warning, GetPerformanceIconForRating(kvp.performanceRating), kvp.issueText, kvp.showThisIssue, kvp.fixThisIssue); + + foreach (var kvp in GUIStats[subject].Where(k => k.performanceRating == PerformanceRating.Good || k.performanceRating == PerformanceRating.Excellent)) + DrawIssueBox(MessageType.Warning, GetPerformanceIconForRating(kvp.performanceRating), kvp.issueText, kvp.showThisIssue, kvp.fixThisIssue); + } + + if (GUIInfos.ContainsKey(subject)) + foreach (Issue error in GUIInfos[subject].Where(s => !string.IsNullOrEmpty(s.issueText))) + EditorGUILayout.HelpBox(error.issueText, MessageType.Info); + if (GUILinks.ContainsKey(subject)) + { + EditorGUILayout.BeginVertical(style); + foreach (Issue error in GUILinks[subject].Where(s => !string.IsNullOrEmpty(s.issueText))) + { + var s = error.issueText.Split('\n'); + EditorGUILayout.BeginHorizontal(); + GUILayout.Label(s[0]); + if (GUILayout.Button("Open Link", GUILayout.Width(100))) + Application.OpenURL(s[1]); + EditorGUILayout.EndHorizontal(); + } + EditorGUILayout.EndVertical(); + } + + if (EditorGUI.EndChangeCheck()) + { + EditorUtility.SetDirty(subject); + UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene()); + } + } + + private Texture GetPerformanceIconForRating(PerformanceRating value) + { + if (_perfIcon_Excellent == null) + _perfIcon_Excellent = Resources.Load<Texture>("PerformanceIcons/Perf_Great_32"); + if (_perfIcon_Good == null) + _perfIcon_Good = Resources.Load<Texture>("PerformanceIcons/Perf_Good_32"); + if (_perfIcon_Medium == null) + _perfIcon_Medium = Resources.Load<Texture>("PerformanceIcons/Perf_Medium_32"); + if (_perfIcon_Poor == null) + _perfIcon_Poor = Resources.Load<Texture>("PerformanceIcons/Perf_Poor_32"); + if (_perfIcon_VeryPoor == null) + _perfIcon_VeryPoor = Resources.Load<Texture>("PerformanceIcons/Perf_Horrible_32"); + + switch (value) + { + case PerformanceRating.Excellent: + return _perfIcon_Excellent; + case PerformanceRating.Good: + return _perfIcon_Good; + case PerformanceRating.Medium: + return _perfIcon_Medium; + case PerformanceRating.Poor: + return _perfIcon_Poor; + case PerformanceRating.None: + case PerformanceRating.VeryPoor: + return _perfIcon_VeryPoor; + } + + return _perfIcon_Excellent; + } + + Texture2D CreateBackgroundColorImage(UnityEngine.Color color) + { + int w = 4, h = 4; + Texture2D back = new Texture2D(w, h); + UnityEngine.Color[] buffer = new UnityEngine.Color[w * h]; + for (int i = 0; i < w; ++i) + for (int j = 0; j < h; ++j) + buffer[i + w * j] = color; + back.SetPixels(buffer); + back.Apply(false); + return back; + } + + public static void DrawContentInfo(string name, string version, string description, string capacity, string releaseStatus, List<string> tags) + { + EditorGUILayout.LabelField("Name: " + name); + EditorGUILayout.LabelField("Version: " + version.ToString()); + EditorGUILayout.LabelField("Description: " + description); + if (capacity != null) + EditorGUILayout.LabelField("Capacity: " + capacity); + EditorGUILayout.LabelField("Release: " + releaseStatus); + if (tags != null) + { + string tagString = ""; + for (int i = 0; i < tags.Count; i++) + { + if (i != 0) tagString += ", "; + tagString += tags[i]; + } + EditorGUILayout.LabelField("Tags: " + tagString); + + } + } + public static void DrawContentPlatformSupport(VRC.Core.ApiModel m) + { + if (m.supportedPlatforms == VRC.Core.ApiModel.SupportedPlatforms.StandaloneWindows || m.supportedPlatforms == VRC.Core.ApiModel.SupportedPlatforms.All) + EditorGUILayout.LabelField("Windows Support: YES"); + else + EditorGUILayout.LabelField("Windows Support: NO"); + + if (m.supportedPlatforms == VRC.Core.ApiModel.SupportedPlatforms.Android || m.supportedPlatforms == VRC.Core.ApiModel.SupportedPlatforms.All) + EditorGUILayout.LabelField("Android Support: YES"); + else + EditorGUILayout.LabelField("Android Support: NO"); + } + + public static void DrawBuildTargetSwitcher() + { + EditorGUILayout.LabelField("Active Build Target: " + EditorUserBuildSettings.activeBuildTarget); + if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneWindows || EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneWindows64 && GUILayout.Button("Switch Build Target to Android")) + { + if (EditorUtility.DisplayDialog("Build Target Switcher", "Are you sure you want to switch your build target to Android? This could take a while.", "Confirm", "Cancel")) + { + EditorUserBuildSettings.selectedBuildTargetGroup = BuildTargetGroup.Android; + EditorUserBuildSettings.SwitchActiveBuildTargetAsync(BuildTargetGroup.Android, BuildTarget.Android); + } + } + if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android && GUILayout.Button("Switch Build Target to Windows")) + { + if (EditorUtility.DisplayDialog("Build Target Switcher", "Are you sure you want to switch your build target to Windows? This could take a while.", "Confirm", "Cancel")) + { + EditorUserBuildSettings.selectedBuildTargetGroup = BuildTargetGroup.Standalone; + EditorUserBuildSettings.SwitchActiveBuildTargetAsync(BuildTargetGroup.Standalone, BuildTarget.StandaloneWindows64); + } + } + } + + public static string GetBuildAndPublishButtonString() + { + string buildButtonString = "Build & Publish for UNSUPPORTED"; + if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneWindows || EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneWindows64) + buildButtonString = "Build & Publish for Windows"; + if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android) + buildButtonString = "Build & Publish for Android"; + + return buildButtonString; + } + + public static Object[] GetSubstanceObjects(GameObject obj = null, bool earlyOut = false) + { + // if 'obj' is null we check entire scene + // if 'earlyOut' is true we only return 1st object (to detect if substances are present) + + List<Object> objects = new List<Object>(); + if (obj == null) return objects.Count < 1 ? null : objects.ToArray(); + Renderer[] renderers = obj ? obj.GetComponentsInChildren<Renderer>(true) : FindObjectsOfType<Renderer>(); + + if (renderers == null || renderers.Length < 1) + return null; + foreach (Renderer r in renderers) + { + if (r.sharedMaterials.Length < 1) + continue; + foreach (Material m in r.sharedMaterials) + { + if (!m) + continue; + string path = AssetDatabase.GetAssetPath(m); + if (string.IsNullOrEmpty(path)) + continue; + if (path.EndsWith(".sbsar", true, System.Globalization.CultureInfo.InvariantCulture)) + { + objects.Add(r.gameObject); + if (earlyOut) + return objects.ToArray(); + } + } + } + + return objects.Count < 1 ? null : objects.ToArray(); + } + + public static bool HasSubstances(GameObject obj = null) + { + return (GetSubstanceObjects(obj, true) != null); + } + + EditorWindow GetLightingWindow() + { + var editorAsm = typeof(UnityEditor.Editor).Assembly; + return EditorWindow.GetWindow(editorAsm.GetType("UnityEditor.LightingWindow")); + } + + public static void ShowContentPublishPermissionsDialog() + { + if (!VRC.Core.ConfigManager.RemoteConfig.IsInitialized()) + { + VRC.Core.ConfigManager.RemoteConfig.Init(() => ShowContentPublishPermissionsDialog()); + return; + } + + string message = VRC.Core.ConfigManager.RemoteConfig.GetString("sdkNotAllowedToPublishMessage"); + int result = UnityEditor.EditorUtility.DisplayDialogComplex("VRChat SDK", message, "Developer FAQ", "VRChat Discord", "OK"); + if (result == 0) + { + ShowDeveloperFAQ(); + } + if (result == 1) + { + ShowVRChatDiscord(); + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelBuilder.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelBuilder.cs.meta new file mode 100644 index 00000000..747cd3d2 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelBuilder.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4c73e735ee0380241b186a8993fa56bf +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelBuilderAttribute.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelBuilderAttribute.cs new file mode 100644 index 00000000..84344b02 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelBuilderAttribute.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using JetBrains.Annotations; +using UnityEngine; + +namespace VRC.SDKBase.Editor +{ + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + [MeansImplicitUse] + public class VRCSdkControlPanelBuilderAttribute : Attribute + { + public Type Type { get; } + public VRCSdkControlPanelBuilderAttribute(Type type) + { + Type = type; + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelBuilderAttribute.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelBuilderAttribute.cs.meta new file mode 100644 index 00000000..32f46ed8 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelBuilderAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c768b42ca9a2f2b48afeb1fa03d5e1bf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelContent.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelContent.cs new file mode 100644 index 00000000..22320b54 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelContent.cs @@ -0,0 +1,690 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using UnityEngine; +using UnityEditor; +using UnityEngine.Networking; +using VRC.Core; + +public partial class VRCSdkControlPanel : EditorWindow +{ + const int PageLimit = 20; + + static List<ApiAvatar> uploadedAvatars = null; + static List<ApiWorld> uploadedWorlds = null; + static List<ApiAvatar> testAvatars = null; + + public static Dictionary<string, Texture2D> ImageCache = new Dictionary<string, Texture2D>(); + + static List<string> justDeletedContents; + static List<ApiAvatar> justUpdatedAvatars; + + static EditorCoroutine fetchingAvatars = null, fetchingWorlds = null; + + private static string searchString = ""; + private static bool WorldsToggle = true; + private static bool AvatarsToggle = true; + private static bool TestAvatarsToggle = true; + + const int SCROLLBAR_RESERVED_REGION_WIDTH = 50; + + const int WORLD_DESCRIPTION_FIELD_WIDTH = 140; + const int WORLD_IMAGE_BUTTON_WIDTH = 100; + const int WORLD_IMAGE_BUTTON_HEIGHT = 100; + const int WORLD_RELEASE_STATUS_FIELD_WIDTH = 150; + const int COPY_WORLD_ID_BUTTON_WIDTH = 75; + const int DELETE_WORLD_BUTTON_WIDTH = 75; + const int WORLD_ALL_INFORMATION_MAX_WIDTH = WORLD_DESCRIPTION_FIELD_WIDTH + WORLD_IMAGE_BUTTON_WIDTH + WORLD_RELEASE_STATUS_FIELD_WIDTH + COPY_WORLD_ID_BUTTON_WIDTH + DELETE_WORLD_BUTTON_WIDTH + SCROLLBAR_RESERVED_REGION_WIDTH; + const int WORLD_REDUCED_INFORMATION_MAX_WIDTH = WORLD_DESCRIPTION_FIELD_WIDTH + WORLD_IMAGE_BUTTON_WIDTH + WORLD_RELEASE_STATUS_FIELD_WIDTH + SCROLLBAR_RESERVED_REGION_WIDTH; + + const int AVATAR_DESCRIPTION_FIELD_WIDTH = 140; + const int AVATAR_IMAGE_BUTTON_WIDTH = WORLD_IMAGE_BUTTON_WIDTH; + const int AVATAR_IMAGE_BUTTON_HEIGHT = WORLD_IMAGE_BUTTON_HEIGHT; + const int AVATAR_RELEASE_STATUS_FIELD_WIDTH = 150; + const int SET_AVATAR_STATUS_BUTTON_WIDTH = 100; + const int COPY_AVATAR_ID_BUTTON_WIDTH = COPY_WORLD_ID_BUTTON_WIDTH; + const int DELETE_AVATAR_BUTTON_WIDTH = DELETE_WORLD_BUTTON_WIDTH; + const int AVATAR_ALL_INFORMATION_MAX_WIDTH = AVATAR_DESCRIPTION_FIELD_WIDTH + AVATAR_IMAGE_BUTTON_WIDTH + AVATAR_RELEASE_STATUS_FIELD_WIDTH + SET_AVATAR_STATUS_BUTTON_WIDTH + COPY_AVATAR_ID_BUTTON_WIDTH + DELETE_AVATAR_BUTTON_WIDTH + SCROLLBAR_RESERVED_REGION_WIDTH; + const int AVATAR_REDUCED_INFORMATION_MAX_WIDTH = AVATAR_DESCRIPTION_FIELD_WIDTH + AVATAR_IMAGE_BUTTON_WIDTH + AVATAR_RELEASE_STATUS_FIELD_WIDTH + SCROLLBAR_RESERVED_REGION_WIDTH; + + const int MAX_ALL_INFORMATION_WIDTH = WORLD_ALL_INFORMATION_MAX_WIDTH > AVATAR_ALL_INFORMATION_MAX_WIDTH ? WORLD_ALL_INFORMATION_MAX_WIDTH : AVATAR_ALL_INFORMATION_MAX_WIDTH; + const int MAX_REDUCED_INFORMATION_WIDTH = WORLD_REDUCED_INFORMATION_MAX_WIDTH > AVATAR_REDUCED_INFORMATION_MAX_WIDTH ? WORLD_REDUCED_INFORMATION_MAX_WIDTH : AVATAR_REDUCED_INFORMATION_MAX_WIDTH; + + public static void ClearContent() + { + if (uploadedWorlds != null) + uploadedWorlds = null; + if (uploadedAvatars != null) + uploadedAvatars = null; + if (testAvatars != null) + testAvatars = null; + ImageCache.Clear(); + } + + IEnumerator FetchUploadedData() + { + if (!ConfigManager.RemoteConfig.IsInitialized()) + ConfigManager.RemoteConfig.Init(); + + if (!APIUser.IsLoggedIn) + yield break; + + ApiCache.ClearResponseCache(); + VRCCachedWebRequest.ClearOld(); + + if (fetchingAvatars == null) + fetchingAvatars = EditorCoroutine.Start(() => FetchAvatars()); + if (fetchingWorlds == null) + fetchingWorlds = EditorCoroutine.Start(() => FetchWorlds()); + FetchTestAvatars(); + } + + private static void FetchAvatars(int offset = 0) + { + ApiAvatar.FetchList( + delegate (IEnumerable<ApiAvatar> obj) + { + if (obj.FirstOrDefault() != null) + fetchingAvatars = EditorCoroutine.Start(() => + { + var l = obj.ToList(); + int count = l.Count; + SetupAvatarData(l); + FetchAvatars(offset + count); + }); + else + { + fetchingAvatars = null; + foreach (ApiAvatar a in uploadedAvatars) + DownloadImage(a.id, a.thumbnailImageUrl); + } + }, + delegate (string obj) + { + Debug.LogError("Error fetching your uploaded avatars:\n" + obj); + fetchingAvatars = null; + }, + ApiAvatar.Owner.Mine, + ApiAvatar.ReleaseStatus.All, + null, + PageLimit, + offset, + ApiAvatar.SortHeading.None, + ApiAvatar.SortOrder.Descending, + null, + null, + true, + false, + null, + false + ); + } + + private static void FetchTestAvatars() + { +#if VRC_SDK_VRCSDK3 + string sdkAvatarFolder = VRC.SDKBase.Editor.VRC_SdkBuilder.GetKnownFolderPath(VRC.SDKBase.Editor.VRC_SdkBuilder.LocalLowGUID) + "/VRChat/vrchat/Avatars/"; + string[] sdkavatars = Directory.GetFiles(sdkAvatarFolder); + string filename = ""; + List<ApiAvatar> avatars = new List<ApiAvatar>(); + foreach(string sdkap in sdkavatars) + { + if(Path.GetExtension(sdkap) != ".vrca") + continue; + + filename = Path.GetFileNameWithoutExtension(sdkap); + ApiAvatar sdka = API.FromCacheOrNew<ApiAvatar>("local:sdk_" + filename); + sdka.assetUrl = sdkap; + sdka.name = filename; + sdka.releaseStatus = "public"; + ApiAvatar.AddLocal(sdka); + avatars.Add(sdka); + } + + testAvatars = avatars; +#else + testAvatars = new List<ApiAvatar>(); +#endif + } + + private static void FetchWorlds(int offset = 0) + { + ApiWorld.FetchList( + delegate (IEnumerable<ApiWorld> obj) + { + if (obj.FirstOrDefault() != null) + fetchingWorlds = EditorCoroutine.Start(() => + { + var l = obj.ToList(); + int count = l.Count; + SetupWorldData(l); + FetchWorlds(offset + count); + }); + else + { + fetchingWorlds = null; + + foreach (ApiWorld w in uploadedWorlds) + DownloadImage(w.id, w.thumbnailImageUrl); + } + }, + delegate (string obj) + { + Debug.LogError("Error fetching your uploaded worlds:\n" + obj); + fetchingWorlds = null; + }, + ApiWorld.SortHeading.Updated, + ApiWorld.SortOwnership.Mine, + ApiWorld.SortOrder.Descending, + offset, + PageLimit, + "", + null, + null, + null, + null, + "", + ApiWorld.ReleaseStatus.All, + null, + null, + true, + false); + } + + static void SetupWorldData(List<ApiWorld> worlds) + { + if (worlds == null || uploadedWorlds == null) + return; + + worlds.RemoveAll(w => w == null || w.name == null || uploadedWorlds.Any(w2 => w2.id == w.id)); + + if (worlds.Count > 0) + { + uploadedWorlds.AddRange(worlds); + uploadedWorlds.Sort((w1, w2) => w1.name.CompareTo(w2.name)); + } + } + + static void SetupAvatarData(List<ApiAvatar> avatars) + { + if (avatars == null || uploadedAvatars == null ) + return; + + avatars.RemoveAll(a => a == null || uploadedAvatars.Any(a2 => a2.id == a.id)); + foreach(var avatar in avatars) + { + if (string.IsNullOrEmpty(avatar.name)) + avatar.name = "(unnamed)"; + } + + if (avatars.Count > 0) + { + uploadedAvatars.AddRange(avatars); + uploadedAvatars.Sort((w1, w2) => w1.name.CompareTo(w2.name)); + } + } + + private static void DownloadImage(string id, string url) + { + if (string.IsNullOrEmpty(url)) + { + return; + } + + if (ImageCache.ContainsKey(id) && ImageCache[id] != null) + { + return; + } + + EditorCoroutine.Start(VRCCachedWebRequest.Get(url, OnDone)); + void OnDone(Texture2D texture) + { + if (texture != null) + { + ImageCache[id] = texture; + } + else if (ImageCache.ContainsKey(id)) + { + ImageCache.Remove(id); + } + } + } + + Vector2 contentScrollPos; + + bool OnGUIUserInfo() + { + bool updatedContent = false; + + if (!ConfigManager.RemoteConfig.IsInitialized()) + ConfigManager.RemoteConfig.Init(); + + if (APIUser.IsLoggedIn && uploadedWorlds != null && uploadedAvatars != null && testAvatars != null) + { + + bool expandedLayout = false; // (position.width > MAX_ALL_INFORMATION_WIDTH); // uncomment for future wide layouts + + if (!expandedLayout) + { + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + } + + GUILayout.BeginHorizontal(); + + GUILayout.BeginVertical(searchBarStyle); + + EditorGUILayout.BeginHorizontal(); + + float searchFieldShrinkOffset = 30f; + GUILayoutOption layoutOption = (expandedLayout ? GUILayout.Width(position.width - searchFieldShrinkOffset) : GUILayout.Width(SdkWindowWidth - searchFieldShrinkOffset)); + searchString = EditorGUILayout.TextField(searchString, GUI.skin.FindStyle("SearchTextField"), layoutOption); + GUIStyle searchButtonStyle = searchString == string.Empty + ? GUI.skin.FindStyle("SearchCancelButtonEmpty") + : GUI.skin.FindStyle("SearchCancelButton"); + if (GUILayout.Button(string.Empty, searchButtonStyle)) + { + searchString = string.Empty; + GUI.FocusControl(null); + } + EditorGUILayout.EndHorizontal(); + EditorGUILayout.EndVertical(); + EditorGUILayout.EndHorizontal(); + + if (!expandedLayout) + { + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + } + + layoutOption = (expandedLayout ? GUILayout.Width(position.width) : GUILayout.Width(SdkWindowWidth)); + contentScrollPos = EditorGUILayout.BeginScrollView(contentScrollPos, layoutOption); + + GUIStyle descriptionStyle = new GUIStyle(EditorStyles.wordWrappedLabel); + descriptionStyle.wordWrap = true; + + if (uploadedWorlds.Count > 0) + { + EditorGUILayout.Space(); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("WORLDS", EditorStyles.boldLabel, GUILayout.ExpandWidth(false), GUILayout.Width(58)); + WorldsToggle = EditorGUILayout.Foldout(WorldsToggle, new GUIContent("")); + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Space(); + + if (WorldsToggle) + { + + List<ApiWorld> tmpWorlds = new List<ApiWorld>(); + + if (uploadedWorlds.Count > 0) + tmpWorlds = new List<ApiWorld>(uploadedWorlds); + + foreach (ApiWorld w in tmpWorlds) + { + if (justDeletedContents != null && justDeletedContents.Contains(w.id)) + { + uploadedWorlds.Remove(w); + continue; + } + + if (!w.name.ToLowerInvariant().Contains(searchString.ToLowerInvariant())) + { + continue; + } + + EditorGUILayout.BeginHorizontal(EditorStyles.helpBox); + EditorGUILayout.BeginHorizontal(GUILayout.Width(WORLD_IMAGE_BUTTON_WIDTH)); + + if (ImageCache.ContainsKey(w.id)) + { + if (GUILayout.Button(ImageCache[w.id], GUILayout.Height(WORLD_IMAGE_BUTTON_HEIGHT), + GUILayout.Width(WORLD_IMAGE_BUTTON_WIDTH))) + { + Application.OpenURL(w.imageUrl); + } + } + else + { + if (GUILayout.Button("", GUILayout.Height(WORLD_IMAGE_BUTTON_HEIGHT), + GUILayout.Width(WORLD_IMAGE_BUTTON_WIDTH))) + { + Application.OpenURL(w.imageUrl); + } + } + + if (expandedLayout) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField(w.name, descriptionStyle, + GUILayout.Width(position.width - MAX_ALL_INFORMATION_WIDTH + + WORLD_DESCRIPTION_FIELD_WIDTH)); + } + else + { + EditorGUILayout.BeginVertical(); + EditorGUILayout.LabelField(w.name, descriptionStyle); + } + + EditorGUILayout.LabelField("Release Status: " + w.releaseStatus, + GUILayout.Width(WORLD_RELEASE_STATUS_FIELD_WIDTH)); + if (GUILayout.Button("Copy ID", GUILayout.Width(COPY_WORLD_ID_BUTTON_WIDTH))) + { + TextEditor te = new TextEditor(); + te.text = w.id; + te.SelectAll(); + te.Copy(); + } + + if (GUILayout.Button("Delete", GUILayout.Width(DELETE_WORLD_BUTTON_WIDTH))) + { + if (EditorUtility.DisplayDialog("Delete " + w.name + "?", + "Are you sure you want to delete " + w.name + "? This cannot be undone.", "Delete", + "Cancel")) + { + foreach (VRC.Core.PipelineManager pm in FindObjectsOfType<VRC.Core.PipelineManager>() + .Where(pm => pm.blueprintId == w.id)) + { + pm.blueprintId = ""; + pm.completedSDKPipeline = false; + + UnityEditor.EditorUtility.SetDirty(pm); + UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(pm.gameObject.scene); + UnityEditor.SceneManagement.EditorSceneManager.SaveScene(pm.gameObject.scene); + } + + API.Delete<ApiWorld>(w.id); + uploadedWorlds.RemoveAll(world => world.id == w.id); + if (ImageCache.ContainsKey(w.id)) + ImageCache.Remove(w.id); + + if (justDeletedContents == null) justDeletedContents = new List<string>(); + justDeletedContents.Add(w.id); + updatedContent = true; + } + } + + if (expandedLayout) + EditorGUILayout.EndHorizontal(); + else + EditorGUILayout.EndVertical(); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + } + } + } + + if (uploadedAvatars.Count > 0) + { + EditorGUILayout.Space(); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("AVATARS", EditorStyles.boldLabel, GUILayout.ExpandWidth(false), GUILayout.Width(65)); + AvatarsToggle = EditorGUILayout.Foldout(AvatarsToggle, new GUIContent("")); + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Space(); + + if (AvatarsToggle) + { + + List<ApiAvatar> tmpAvatars = new List<ApiAvatar>(); + + if (uploadedAvatars.Count > 0) + tmpAvatars = new List<ApiAvatar>(uploadedAvatars); + + if (justUpdatedAvatars != null) + { + foreach (ApiAvatar a in justUpdatedAvatars) + { + int index = tmpAvatars.FindIndex((av) => av.id == a.id); + if (index != -1) + tmpAvatars[index] = a; + } + } + + foreach (ApiAvatar a in tmpAvatars) + { + if (justDeletedContents != null && justDeletedContents.Contains(a.id)) + { + uploadedAvatars.Remove(a); + continue; + } + + if (!a.name.ToLowerInvariant().Contains(searchString.ToLowerInvariant())) + { + continue; + } + + EditorGUILayout.BeginHorizontal(EditorStyles.helpBox); + EditorGUILayout.BeginHorizontal(GUILayout.Width(AVATAR_DESCRIPTION_FIELD_WIDTH)); + if (ImageCache.ContainsKey(a.id)) + { + if (GUILayout.Button(ImageCache[a.id], GUILayout.Height(AVATAR_IMAGE_BUTTON_HEIGHT), + GUILayout.Width(AVATAR_IMAGE_BUTTON_WIDTH))) + { + Application.OpenURL(a.imageUrl); + } + } + else + { + if (GUILayout.Button("", GUILayout.Height(AVATAR_IMAGE_BUTTON_HEIGHT), + GUILayout.Width(AVATAR_IMAGE_BUTTON_WIDTH))) + { + Application.OpenURL(a.imageUrl); + } + } + + if (expandedLayout) + EditorGUILayout.BeginHorizontal(); + else + EditorGUILayout.BeginVertical(); + + EditorGUILayout.LabelField(a.name, descriptionStyle, + GUILayout.Width(expandedLayout + ? position.width - MAX_ALL_INFORMATION_WIDTH + AVATAR_DESCRIPTION_FIELD_WIDTH + : AVATAR_DESCRIPTION_FIELD_WIDTH)); + EditorGUILayout.LabelField("Release Status: " + a.releaseStatus, + GUILayout.Width(AVATAR_RELEASE_STATUS_FIELD_WIDTH)); + + string oppositeReleaseStatus = a.releaseStatus == "public" ? "private" : "public"; + if (GUILayout.Button("Make " + oppositeReleaseStatus, + GUILayout.Width(SET_AVATAR_STATUS_BUTTON_WIDTH))) + { + a.releaseStatus = oppositeReleaseStatus; + + a.SaveReleaseStatus((c) => + { + ApiAvatar savedBP = (ApiAvatar) c.Model; + + if (justUpdatedAvatars == null) justUpdatedAvatars = new List<ApiAvatar>(); + justUpdatedAvatars.Add(savedBP); + + }, + (c) => + { + Debug.LogError(c.Error); + EditorUtility.DisplayDialog("Avatar Updated", + "Failed to change avatar release status", "OK"); + }); + } + + if (GUILayout.Button("Copy ID", GUILayout.Width(COPY_AVATAR_ID_BUTTON_WIDTH))) + { + TextEditor te = new TextEditor(); + te.text = a.id; + te.SelectAll(); + te.Copy(); + } + + if (GUILayout.Button("Delete", GUILayout.Width(DELETE_AVATAR_BUTTON_WIDTH))) + { + if (EditorUtility.DisplayDialog("Delete " + a.name + "?", + "Are you sure you want to delete " + a.name + "? This cannot be undone.", "Delete", + "Cancel")) + { + foreach (VRC.Core.PipelineManager pm in FindObjectsOfType<VRC.Core.PipelineManager>() + .Where(pm => pm.blueprintId == a.id)) + { + pm.blueprintId = ""; + pm.completedSDKPipeline = false; + + UnityEditor.EditorUtility.SetDirty(pm); + UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(pm.gameObject.scene); + UnityEditor.SceneManagement.EditorSceneManager.SaveScene(pm.gameObject.scene); + } + + API.Delete<ApiAvatar>(a.id); + uploadedAvatars.RemoveAll(avatar => avatar.id == a.id); + if (ImageCache.ContainsKey(a.id)) + ImageCache.Remove(a.id); + + if (justDeletedContents == null) justDeletedContents = new List<string>(); + justDeletedContents.Add(a.id); + updatedContent = true; + } + } + + if (expandedLayout) + EditorGUILayout.EndHorizontal(); + else + EditorGUILayout.EndVertical(); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + } + } + } + + if (testAvatars.Count > 0) + { + EditorGUILayout.Space(); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Test Avatars", EditorStyles.boldLabel, GUILayout.ExpandWidth(false), GUILayout.Width(100)); + TestAvatarsToggle = EditorGUILayout.Foldout(TestAvatarsToggle, new GUIContent("")); + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Space(); + + if (TestAvatarsToggle) + { + List<ApiAvatar> tmpAvatars = new List<ApiAvatar>(); + + if (testAvatars.Count > 0) + tmpAvatars = new List<ApiAvatar>(testAvatars); + + foreach (ApiAvatar a in tmpAvatars) + { + if (!a.name.ToLowerInvariant().Contains(searchString.ToLowerInvariant())) + { + continue; + } + + EditorGUILayout.BeginHorizontal(EditorStyles.helpBox); + + if (expandedLayout) + EditorGUILayout.BeginHorizontal(); + else + EditorGUILayout.BeginVertical(); + + EditorGUILayout.LabelField(a.name, descriptionStyle, + GUILayout.Width(expandedLayout + ? position.width - MAX_ALL_INFORMATION_WIDTH + AVATAR_DESCRIPTION_FIELD_WIDTH + : AVATAR_DESCRIPTION_FIELD_WIDTH)); + + if (GUILayout.Button("Delete", GUILayout.Width(DELETE_AVATAR_BUTTON_WIDTH))) + { + if (EditorUtility.DisplayDialog("Delete " + a.name + "?", + "Are you sure you want to delete " + a.name + "? This cannot be undone.", "Delete", + "Cancel")) + { + API.Delete<ApiAvatar>(a.id); + testAvatars.RemoveAll(avatar => avatar.id == a.id); + File.Delete(a.assetUrl); + + updatedContent = true; + } + } + + if (expandedLayout) + EditorGUILayout.EndHorizontal(); + else + EditorGUILayout.EndVertical(); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + } + } + } + + EditorGUILayout.EndScrollView(); + if (!expandedLayout) + { + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + } + if ((updatedContent) && (null != window)) window.Reset(); + + return true; + } + else + { + return false; + } + } + + void ShowContent() + { + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.BeginVertical(); + + if (uploadedWorlds == null || uploadedAvatars == null || testAvatars == null) + { + if (uploadedWorlds == null) + uploadedWorlds = new List<ApiWorld>(); + if (uploadedAvatars == null) + uploadedAvatars = new List<ApiAvatar>(); + if (testAvatars == null) + testAvatars = new List<ApiAvatar>(); + + EditorCoroutine.Start(FetchUploadedData()); + } + + if( fetchingWorlds != null || fetchingAvatars != null ) + { + GUILayout.BeginVertical(boxGuiStyle, GUILayout.Width(SdkWindowWidth)); + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Fetching Records", titleGuiStyle); + EditorGUILayout.Space(); + GUILayout.EndVertical(); + } + else + { + GUILayout.BeginVertical(boxGuiStyle, GUILayout.Width(SdkWindowWidth)); + EditorGUILayout.Space(); + EditorGUILayout.BeginHorizontal(); + GUILayout.Label("Fetch updated records from the VRChat server"); + if( GUILayout.Button("Fetch") ) + { + ClearContent(); + } + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + GUILayout.EndVertical(); + } + + GUILayout.EndVertical(); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + OnGUIUserInfo(); + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelContent.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelContent.cs.meta new file mode 100644 index 00000000..705c058d --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelContent.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c7333cdb3df19724b84b4a1b05093fe0 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelHelp.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelHelp.cs new file mode 100644 index 00000000..20db725e --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelHelp.cs @@ -0,0 +1,59 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEngine; +using VRC; +using VRC.Core; +using VRC.SDKBase; + +public partial class VRCSdkControlPanel : EditorWindow +{ + [MenuItem("VRChat SDK/Help/Developer FAQ")] + public static void ShowDeveloperFAQ() + { + if (!ConfigManager.RemoteConfig.IsInitialized()) + { + ConfigManager.RemoteConfig.Init(() => ShowDeveloperFAQ()); + return; + } + + Application.OpenURL(ConfigManager.RemoteConfig.GetString("sdkDeveloperFaqUrl")); + } + + [MenuItem("VRChat SDK/Help/VRChat Discord")] + public static void ShowVRChatDiscord() + { + if (!ConfigManager.RemoteConfig.IsInitialized()) + { + ConfigManager.RemoteConfig.Init(() => ShowVRChatDiscord()); + return; + } + + Application.OpenURL(ConfigManager.RemoteConfig.GetString("sdkDiscordUrl")); + } + + [MenuItem("VRChat SDK/Help/Avatar Optimization Tips")] + public static void ShowAvatarOptimizationTips() + { + if (!ConfigManager.RemoteConfig.IsInitialized()) + { + ConfigManager.RemoteConfig.Init(() => ShowAvatarOptimizationTips()); + return; + } + + Application.OpenURL(AVATAR_OPTIMIZATION_TIPS_URL); + } + + [MenuItem("VRChat SDK/Help/Avatar Rig Requirements")] + public static void ShowAvatarRigRequirements() + { + if (!ConfigManager.RemoteConfig.IsInitialized()) + { + ConfigManager.RemoteConfig.Init(() => ShowAvatarRigRequirements()); + return; + } + + Application.OpenURL(AVATAR_RIG_REQUIREMENTS_URL); + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelHelp.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelHelp.cs.meta new file mode 100644 index 00000000..a201ff75 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelHelp.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f3507a74e4b8cfd469afac127fa5f4e5 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelSettings.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelSettings.cs new file mode 100644 index 00000000..2df9b7c5 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelSettings.cs @@ -0,0 +1,260 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using VRC.Core; +using VRC.SDKBase.Editor; + +public partial class VRCSdkControlPanel : EditorWindow +{ + bool UseDevApi + { + get + { + return VRC.Core.API.GetApiUrl() == VRC.Core.API.devApiUrl; + } + } + + string clientVersionDate; + string sdkVersionDate; + Vector2 settingsScroll; + + private void Awake() + { + GetClientSdkVersionInformation(); + } + + public void GetClientSdkVersionInformation() + { + clientVersionDate = VRC.Core.SDKClientUtilities.GetTestClientVersionDate(); + sdkVersionDate = VRC.Core.SDKClientUtilities.GetSDKVersionDate(); + } + + public void OnConfigurationChanged() + { + GetClientSdkVersionInformation(); + } + + void ShowSettings() + { + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.BeginVertical(); + + settingsScroll = EditorGUILayout.BeginScrollView(settingsScroll, GUILayout.Width(SdkWindowWidth)); + + EditorGUILayout.BeginVertical(boxGuiStyle); + EditorGUILayout.LabelField("Developer", EditorStyles.boldLabel); + + VRCSettings.DisplayAdvancedSettings = EditorGUILayout.ToggleLeft("Show Extra Options on build page and account page", VRCSettings.DisplayAdvancedSettings); + bool prevDisplayHelpBoxes = VRCSettings.DisplayHelpBoxes; + VRCSettings.DisplayHelpBoxes = EditorGUILayout.ToggleLeft("Show Help Boxes on SDK components", VRCSettings.DisplayHelpBoxes); + if (VRCSettings.DisplayHelpBoxes != prevDisplayHelpBoxes) + { + Editor[] editors = (Editor[])Resources.FindObjectsOfTypeAll<Editor>(); + for (int i = 0; i < editors.Length; i++) + { + editors[i].Repaint(); + } + } + EditorGUILayout.EndVertical(); + + EditorGUILayout.Separator(); + + ShowSdk23CompatibilitySettings(); + EditorGUILayout.Separator(); + + ShowSettingsOptionsForBuilders(); + + + // debugging + if (APIUser.CurrentUser != null && APIUser.CurrentUser.hasSuperPowers) + { + EditorGUILayout.Separator(); + EditorGUILayout.BeginVertical(boxGuiStyle); + + EditorGUILayout.LabelField("Logging", EditorStyles.boldLabel); + + // API logging + { + bool isLoggingEnabled = UnityEditor.EditorPrefs.GetBool("apiLoggingEnabled"); + bool enableLogging = EditorGUILayout.ToggleLeft("API Logging Enabled", isLoggingEnabled); + if (enableLogging != isLoggingEnabled) + { + if (enableLogging) + VRC.Core.Logger.AddDebugLevel(DebugLevel.API); + else + VRC.Core.Logger.RemoveDebugLevel(DebugLevel.API); + + UnityEditor.EditorPrefs.SetBool("apiLoggingEnabled", enableLogging); + } + } + + // All logging + { + bool isLoggingEnabled = UnityEditor.EditorPrefs.GetBool("allLoggingEnabled"); + bool enableLogging = EditorGUILayout.ToggleLeft("All Logging Enabled", isLoggingEnabled); + if (enableLogging != isLoggingEnabled) + { + if (enableLogging) + VRC.Core.Logger.AddDebugLevel(DebugLevel.All); + else + VRC.Core.Logger.RemoveDebugLevel(DebugLevel.All); + + UnityEditor.EditorPrefs.SetBool("allLoggingEnabled", enableLogging); + } + } + EditorGUILayout.EndVertical(); + } + else + { + if (UnityEditor.EditorPrefs.GetBool("apiLoggingEnabled")) + UnityEditor.EditorPrefs.SetBool("apiLoggingEnabled", false); + if (UnityEditor.EditorPrefs.GetBool("allLoggingEnabled")) + UnityEditor.EditorPrefs.SetBool("allLoggingEnabled", false); + } + + // Future proof upload + { + EditorGUILayout.Separator(); + EditorGUILayout.BeginVertical(boxGuiStyle); + + EditorGUILayout.LabelField("Publish", EditorStyles.boldLabel); + bool futureProofPublish = UnityEditor.EditorPrefs.GetBool("futureProofPublish", DefaultFutureProofPublishEnabled); + + futureProofPublish = EditorGUILayout.ToggleLeft("Future Proof Publish", futureProofPublish); + + if (UnityEditor.EditorPrefs.GetBool("futureProofPublish", DefaultFutureProofPublishEnabled) != futureProofPublish) + { + UnityEditor.EditorPrefs.SetBool("futureProofPublish", futureProofPublish); + } + EditorGUILayout.LabelField("Client Version Date", clientVersionDate); + EditorGUILayout.LabelField("SDK Version Date", sdkVersionDate); + + EditorGUILayout.EndVertical(); + } + + + if (APIUser.CurrentUser != null) + { + EditorGUILayout.Separator(); + EditorGUILayout.BeginVertical(boxGuiStyle); + + // custom vrchat install location + OnVRCInstallPathGUI(); + + EditorGUILayout.EndVertical(); + } + + EditorGUILayout.EndScrollView(); + + GUILayout.EndVertical(); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + } + + static void OnVRCInstallPathGUI() + { + EditorGUILayout.LabelField("VRChat Client", EditorStyles.boldLabel); + EditorGUILayout.LabelField("Installed Client Path: ", clientInstallPath); + EditorGUILayout.BeginHorizontal(); + GUILayout.Label(""); + if (GUILayout.Button("Edit")) + { + string initPath = ""; + if (!string.IsNullOrEmpty(clientInstallPath)) + initPath = clientInstallPath; + + clientInstallPath = EditorUtility.OpenFilePanel("Choose VRC Client Exe", initPath, "exe"); + SDKClientUtilities.SetVRCInstallPath(clientInstallPath); + window.OnConfigurationChanged(); + } + if (GUILayout.Button("Revert to Default")) + { + clientInstallPath = SDKClientUtilities.LoadRegistryVRCInstallPath(); + window.OnConfigurationChanged(); + } + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Separator(); + } + + static void ShowSdk23CompatibilitySettings() + { + return; + +// EditorGUILayout.BeginVertical(boxGuiStyle); +// EditorGUILayout.LabelField("VRCSDK2 & VRCSDK3 Compatibility", EditorStyles.boldLabel); + +//#if !VRC_CLIENT +// bool sdk2Present = VRCSdk3Analysis.GetSDKInScene(VRCSdk3Analysis.SdkVersion.VRCSDK2).Count > 0; +// bool sdk3Present = VRCSdk3Analysis.GetSDKInScene(VRCSdk3Analysis.SdkVersion.VRCSDK3).Count > 0; +// bool sdk2DllActive = VRCSdk3Analysis.IsSdkDllActive(VRCSdk3Analysis.SdkVersion.VRCSDK2); +// bool sdk3DllActive = VRCSdk3Analysis.IsSdkDllActive(VRCSdk3Analysis.SdkVersion.VRCSDK3); + +// if ( sdk2DllActive && sdk3DllActive) +// { +// GUILayout.TextArea("You have not yet configured this project for development with VRCSDK2 and Triggers or VRCSDK3 and Udon. "); +// if (sdk2Present && sdk3Present) +// { +// GUILayout.TextArea("This scene contains both SDK2 and SDK3 elements. " + +// "Please modify this scene to contain only one type or the other before completing your configuration."); +// } +// else if (sdk2Present) +// { +// GUILayout.TextArea("This scene contains SDK2 scripts. " + +// "Check below to configure this project for use with VRCSDK2 or remove your VRCSDK2 scripts to upgrade to VRCSDK3"); +// bool downgrade = EditorGUILayout.ToggleLeft("Configure for use with VRCSDK2 and Triggers", false); +// if (downgrade) +// VRCSdk3Analysis.SetSdkVersionActive(VRCSdk3Analysis.SdkVersion.VRCSDK2); +// } +// else if (sdk3Present) +// { +// GUILayout.TextArea("This scene contains only SDK3 scripts and it ready to upgrade. " + +// "Click below to get started."); +// bool upgrade = EditorGUILayout.ToggleLeft("Configure for use with VRCSDK3 and Udon - Let's Rock!", false); +// if (upgrade) +// VRCSdk3Analysis.SetSdkVersionActive(VRCSdk3Analysis.SdkVersion.VRCSDK3); +// } +// else +// { +// GUILayout.TextArea("This scene is a blank slate. " + +// "Click below to get started."); +// bool upgrade = EditorGUILayout.ToggleLeft("Configure for use with VRCSDK3 and Udon - Let's Rock!", false); +// if (upgrade) +// VRCSdk3Analysis.SetSdkVersionActive(VRCSdk3Analysis.SdkVersion.VRCSDK3); +// } +// } +// else if (sdk2DllActive) +// { +// GUILayout.TextArea("This project has been configured to be built with VRCSDK2. " + +// "To upgrade, VRCSDK3 must be enabled here."); +// bool upgrade = EditorGUILayout.ToggleLeft("VRCSDK3 Scripts can be used", false); +// if (upgrade) +// VRCSdk3Analysis.SetSdkVersionActive(VRCSdk3Analysis.SdkVersion.VRCSDK3); +// } +// else if (sdk3DllActive) +// { +// GUILayout.TextArea("This project has been configured to be built with VRCSDK3. " + +// "Congratulations, you're ready to go. " + +// "You can still downgrade by activating VRCSDK2 here."); +// bool downgrade = EditorGUILayout.ToggleLeft("VRCSDK2 Scripts can be used", false); +// if (downgrade) +// VRCSdk3Analysis.SetSdkVersionActive(VRCSdk3Analysis.SdkVersion.VRCSDK2); +// } +// else +// { +// GUILayout.TextArea("Somehow you have disabled both VRCSDK2 and VRCSDK3. Oops. " + +// "Click here to begin development with VRCSDK3."); +// bool begin = EditorGUILayout.ToggleLeft("VRCSDK3 Scripts can be used", false); +// if (begin) +// VRCSdk3Analysis.SetSdkVersionActive(VRCSdk3Analysis.SdkVersion.VRCSDK3); +// } +//#else +// GUILayout.TextArea("I think you're in the main VRChat project. " + +// "You should not be enabling or disabling SDKs from here."); +//#endif + +// EditorGUILayout.EndVertical(); + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelSettings.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelSettings.cs.meta new file mode 100644 index 00000000..0dd5e76d --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ControlPanel/VRCSdkControlPanelSettings.cs.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8357b9b7ef2416946ae86f465a64c0e0 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/EnvConfig.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/EnvConfig.cs new file mode 100644 index 00000000..3337377d --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/EnvConfig.cs @@ -0,0 +1,1272 @@ +#define ENV_SET_INCLUDED_SHADERS + +using UnityEngine; +using UnityEditor; +using System.Collections; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEngine.Rendering; +using VRC.SDKBase.Validation.Performance.Stats; +using Object = UnityEngine.Object; + +/// <summary> +/// Setup up SDK env on editor launch +/// </summary> +[InitializeOnLoad] +public class EnvConfig +{ + private static readonly BuildTarget[] relevantBuildTargets = + { + BuildTarget.Android, + BuildTarget.iOS, + BuildTarget.StandaloneLinux64, + BuildTarget.StandaloneWindows, BuildTarget.StandaloneWindows64, + BuildTarget.StandaloneOSX + }; + + #if !VRC_CLIENT + private static readonly BuildTarget[] allowedBuildtargets = { + BuildTarget.StandaloneWindows64, + BuildTarget.Android + }; + #endif + + private static readonly Dictionary<BuildTarget, GraphicsDeviceType[]> allowedGraphicsAPIs = new Dictionary<BuildTarget, GraphicsDeviceType[]>() + { + {BuildTarget.Android, new[] {GraphicsDeviceType.OpenGLES3, /* GraphicsDeviceType.Vulkan */}}, + {BuildTarget.iOS, null}, + {BuildTarget.StandaloneLinux64, null}, + {BuildTarget.StandaloneWindows, new[] {GraphicsDeviceType.Direct3D11}}, + {BuildTarget.StandaloneWindows64, new[] {GraphicsDeviceType.Direct3D11}}, + {BuildTarget.StandaloneOSX, null} + }; + + #if ENV_SET_INCLUDED_SHADERS && VRC_CLIENT + private static readonly string[] ensureTheseShadersAreAvailable = + { + "Hidden/CubeBlend", + "Hidden/CubeBlur", + "Hidden/CubeCopy", + "Hidden/VideoDecode", + "Legacy Shaders/Bumped Diffuse", + "Legacy Shaders/Bumped Specular", + "Legacy Shaders/Decal", + "Legacy Shaders/Diffuse Detail", + "Legacy Shaders/Diffuse Fast", + "Legacy Shaders/Diffuse", + "Legacy Shaders/Diffuse", + "Legacy Shaders/Lightmapped/Diffuse", + "Legacy Shaders/Lightmapped/Specular", + "Legacy Shaders/Lightmapped/VertexLit", + "Legacy Shaders/Parallax Diffuse", + "Legacy Shaders/Parallax Specular", + "Legacy Shaders/Reflective/Bumped Diffuse", + "Legacy Shaders/Reflective/Bumped Specular", + "Legacy Shaders/Reflective/Bumped Unlit", + "Legacy Shaders/Reflective/Bumped VertexLit", + "Legacy Shaders/Reflective/Diffuse", + "Legacy Shaders/Reflective/Parallax Diffuse", + "Legacy Shaders/Reflective/Parallax Specular", + "Legacy Shaders/Reflective/Specular", + "Legacy Shaders/Reflective/VertexLit", + "Legacy Shaders/Self-Illumin/Bumped Diffuse", + "Legacy Shaders/Self-Illumin/Bumped Specular", + "Legacy Shaders/Self-Illumin/Diffuse", + "Legacy Shaders/Self-Illumin/Parallax Diffuse", + "Legacy Shaders/Self-Illumin/Parallax Specular", + "Legacy Shaders/Self-Illumin/Specular", + "Legacy Shaders/Self-Illumin/VertexLit", + "Legacy Shaders/Specular", + "Legacy Shaders/Transparent/Bumped Diffuse", + "Legacy Shaders/Transparent/Bumped Specular", + "Legacy Shaders/Transparent/Cutout/Bumped Diffuse", + "Legacy Shaders/Transparent/Cutout/Bumped Specular", + "Legacy Shaders/Transparent/Cutout/Diffuse", + "Legacy Shaders/Transparent/Cutout/Soft Edge Unlit", + "Legacy Shaders/Transparent/Cutout/Specular", + "Legacy Shaders/Transparent/Cutout/VertexLit", + "Legacy Shaders/Transparent/Diffuse", + "Legacy Shaders/Transparent/Parallax Diffuse", + "Legacy Shaders/Transparent/Parallax Specular", + "Legacy Shaders/Transparent/Specular", + "Legacy Shaders/Transparent/VertexLit", + "Legacy Shaders/VertexLit", + "Legacy Shaders/Particles/Additive", + "Legacy Shaders/Particles/~Additive-Multiply", + "Legacy Shaders/Particles/Additive (Soft)", + "Legacy Shaders/Particles/Alpha Blended", + "Legacy Shaders/Particles/Anim Alpha Blended", + "Legacy Shaders/Particles/Multiply", + "Legacy Shaders/Particles/Multiply (Double)", + "Legacy Shaders/Particles/Alpha Blended Premultiply", + "Legacy Shaders/Particles/VertexLit Blended", + "Mobile/Particles/Additive", + "Mobile/Particles/Alpha Blended", + "Mobile/Particles/Multiply", + "Mobile/Particles/VertexLit Blended", + "Mobile/Skybox", + "Nature/Terrain/Diffuse", + "Nature/Terrain/Specular", + "Nature/Terrain/Standard", + "Particles/Additive (Soft)", + "Particles/Additive", + "Particles/Alpha Blended Premultiply", + "Particles/Alpha Blended", + "Particles/Anim Alpha Blended", + "Particles/Multiply (Double)", + "Particles/Multiply", + "Particles/VertexLit Blended", + "Particles/~Additive-Multiply", + "Skybox/Cubemap", + "Skybox/Procedural", + "Skybox/6 Sided", + "Sprites/Default", + "Sprites/Diffuse", + "UI/Default", + "VRChat/UI/Unlit/WebPanelTransparent", + "Toon/Lit", + "Toon/Lit (Double)", + "Toon/Lit Cutout", + "Toon/Lit Cutout (Double)", + "Toon/Lit Outline", + "VRChat/Mobile/Diffuse", + "Video/RealtimeEmissiveGamma", + "VRChat/PC/Toon Lit", + "VRChat/PC/Toon Lit (Double)", + "VRChat/PC/Toon Lit Cutout", + "VRChat/PC/Toon Lit Cutout (Double)", + "Unlit/Color", + "Unlit/Transparent", + "Unlit/Transparent Cutout", + "Unlit/Texture", + "MatCap/Vertex/Textured Lit", + "VRChat/Mobile/Bumped Uniform Diffuse", + "VRChat/Mobile/Bumped Uniform Specular", + "VRChat/Mobile/Toon Lit", + "VRChat/Mobile/MatCap Lit", + "VRChat/Mobile/Skybox", + "VRChat/Mobile/Lightmapped", + "VRChat/Mobile/Bumped Mapped Specular", + "VRChat/Mobile/Diffuse", + "VRChat/Mobile/Particles/Additive", + "VRChat/Mobile/Particles/Multiply", + "VRChat/Mobile/Standard Lite", + "TextMeshPro/Distance Field (Surface)", + "TextMeshPro/Mobile/Distance Field (No ZTest)", + "TextMeshPro/Distance Field Overlay", + "TextMeshPro/Sprite", + "TextMeshPro/Mobile/Distance Field - Masking", + "TextMeshPro/Mobile/Distance Field Overlay", + "TextMeshPro/Mobile/Distance Field (Surface)", + "TextMeshPro/Mobile/Distance Field", + "TextMeshPro/Distance Field", + "TextMeshPro/Bitmap Custom Atlas", + "VRChat/UI/TextMeshPro/Mobile/Distance Field", + "TextMeshPro/Mobile/Bitmap", + "TextMeshPro/Bitmap", + "TextMeshPro/Mobile/Distance Field - Masking (NoZTest)" + }; + #endif + + private static bool _requestConfigureSettings = true; + + static EnvConfig() + { + EditorApplication.update += EditorUpdate; + } + + private static void EditorUpdate() + { + if(!_requestConfigureSettings) + { + return; + } + + if(ConfigureSettings()) + { + _requestConfigureSettings = false; + } + } + + public static void RequestConfigureSettings() + { + _requestConfigureSettings = true; + } + + [UnityEditor.Callbacks.DidReloadScripts(int.MaxValue)] + private static void DidReloadScripts() + { + RequestConfigureSettings(); + } + + public static bool ConfigureSettings() + { + CheckForFirstInit(); + + if(EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isUpdating) + { + return false; + } + + ConfigurePlayerSettings(); + + if(!VRC.Core.ConfigManager.RemoteConfig.IsInitialized()) + { + VRC.Core.API.SetOnlineMode(true, "vrchat"); + VRC.Core.ConfigManager.RemoteConfig.Init(); + } + + ConfigureAssets(); + + LoadEditorResources(); + + return true; + } + + #if !VRC_CLIENT + private static void SetDLLPlatforms(string dllName, bool active) + { + string[] assetGuids = AssetDatabase.FindAssets(dllName); + + foreach(string guid in assetGuids) + { + string dllPath = AssetDatabase.GUIDToAssetPath(guid); + if(string.IsNullOrEmpty(dllPath) || dllPath.ToLower().EndsWith(".dll") == false) + { + return; + } + + PluginImporter importer = AssetImporter.GetAtPath(dllPath) as PluginImporter; + if(importer == null) + { + return; + } + + bool allCorrect = true; + if(importer.GetCompatibleWithAnyPlatform() != active) + { + allCorrect = false; + } + else + { + if(importer.GetCompatibleWithAnyPlatform()) + { + if(importer.GetExcludeEditorFromAnyPlatform() != !active || + importer.GetExcludeFromAnyPlatform(BuildTarget.StandaloneWindows) != !active) + { + allCorrect = false; + } + } + else + { + if(importer.GetCompatibleWithEditor() != active || + importer.GetCompatibleWithPlatform(BuildTarget.StandaloneWindows) != active) + { + allCorrect = false; + } + } + } + + if(allCorrect) + { + continue; + } + + if(active) + { + importer.SetCompatibleWithAnyPlatform(true); + importer.SetExcludeEditorFromAnyPlatform(false); + importer.SetExcludeFromAnyPlatform(BuildTarget.Android, false); + importer.SetExcludeFromAnyPlatform(BuildTarget.StandaloneWindows, false); + importer.SetExcludeFromAnyPlatform(BuildTarget.StandaloneWindows64, false); + importer.SetExcludeFromAnyPlatform(BuildTarget.StandaloneLinux64, false); + } + else + { + importer.SetCompatibleWithAnyPlatform(false); + importer.SetCompatibleWithEditor(false); + importer.SetCompatibleWithPlatform(BuildTarget.Android, false); + importer.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows, false); + importer.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows64, false); + importer.SetCompatibleWithPlatform(BuildTarget.StandaloneLinux64, false); + } + + importer.SaveAndReimport(); + } + } + #endif + + [MenuItem("VRChat SDK/Utilities/Force Configure Player Settings")] + public static void ConfigurePlayerSettings() + { + VRC.Core.Logger.Log("Setting required PlayerSettings...", VRC.Core.DebugLevel.All); + + SetBuildTarget(); + + // Needed for Microsoft.CSharp namespace in DLLMaker + // Doesn't seem to work though + if(PlayerSettings.GetApiCompatibilityLevel(EditorUserBuildSettings.selectedBuildTargetGroup) != ApiCompatibilityLevel.NET_4_6) + { + PlayerSettings.SetApiCompatibilityLevel(EditorUserBuildSettings.selectedBuildTargetGroup, ApiCompatibilityLevel.NET_4_6); + } + + if(!PlayerSettings.runInBackground) + { + PlayerSettings.runInBackground = true; + } + + #if !VRC_CLIENT + SetDLLPlatforms("VRCCore-Standalone", false); + SetDLLPlatforms("VRCCore-Editor", true); + #endif + + SetDefaultGraphicsAPIs(); + SetGraphicsSettings(); + SetQualitySettings(); + SetAudioSettings(); + SetPlayerSettings(); + + #if VRC_CLIENT + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + PlatformSwitcher.RefreshRequiredPackages(EditorUserBuildSettings.selectedBuildTargetGroup); + #else + // SDK + + // default to steam runtime in sdk (shouldn't matter) + SetVRSDKs(EditorUserBuildSettings.selectedBuildTargetGroup, new string[] { "None", "OpenVR", "Oculus" }); + + VRC.Core.AnalyticsSDK.Initialize(VRC.Core.SDKClientUtilities.GetSDKVersionDate()); + #endif + + #if VRC_CLIENT + // VRCLog should handle disk writing + PlayerSettings.usePlayerLog = false; + foreach(LogType logType in Enum.GetValues(typeof(LogType)).Cast<LogType>()) + { + switch(logType) + { + case LogType.Assert: + case LogType.Exception: + { + PlayerSettings.SetStackTraceLogType(logType, StackTraceLogType.ScriptOnly); + break; + } + case LogType.Error: + case LogType.Warning: + case LogType.Log: + { + #if UNITY_EDITOR + PlayerSettings.SetStackTraceLogType(logType, StackTraceLogType.ScriptOnly); + #else + PlayerSettings.SetStackTraceLogType(logType, StackTraceLogType.None); + #endif + break; + } + default: + { + throw new ArgumentOutOfRangeException(); + } + } + } + #endif + } + + private static void EnableBatching(bool enable) + { + PlayerSettings[] playerSettings = Resources.FindObjectsOfTypeAll<PlayerSettings>(); + if(playerSettings == null) + { + return; + } + + SerializedObject playerSettingsSerializedObject = new SerializedObject(playerSettings.Cast<UnityEngine.Object>().ToArray()); + SerializedProperty batchingSettings = playerSettingsSerializedObject.FindProperty("m_BuildTargetBatching"); + if(batchingSettings == null) + { + return; + } + + for(int i = 0; i < batchingSettings.arraySize; i++) + { + SerializedProperty batchingArrayValue = batchingSettings.GetArrayElementAtIndex(i); + + IEnumerator batchingEnumerator = batchingArrayValue?.GetEnumerator(); + if(batchingEnumerator == null) + { + continue; + } + + while(batchingEnumerator.MoveNext()) + { + SerializedProperty property = (SerializedProperty)batchingEnumerator.Current; + + if(property != null && property.name == "m_BuildTarget") + { + // only change setting on "Standalone" entry + if(property.stringValue != "Standalone") + { + break; + } + } + + if(property != null && property.name == "m_StaticBatching") + { + property.boolValue = enable; + } + + if(property != null && property.name == "m_DynamicBatching") + { + property.boolValue = enable; + } + } + } + + playerSettingsSerializedObject.ApplyModifiedProperties(); + } + + public static void SetVRSDKs(BuildTargetGroup buildTargetGroup, string[] sdkNames) + { + VRC.Core.Logger.Log("Setting virtual reality SDKs in PlayerSettings: ", VRC.Core.DebugLevel.All); + if(sdkNames != null) + { + foreach(string s in sdkNames) + { + VRC.Core.Logger.Log("- " + s, VRC.Core.DebugLevel.All); + } + } + + if (!EditorApplication.isPlaying) + { + #pragma warning disable 618 + PlayerSettings.SetVirtualRealitySDKs(buildTargetGroup, sdkNames); + #pragma warning restore 618 + } + } + + public static bool CheckForFirstInit() + { + bool firstLaunch = SessionState.GetBool("EnvConfigFirstLaunch", true); + if(firstLaunch) + { + SessionState.SetBool("EnvConfigFirstLaunch", false); + } + + return firstLaunch; + } + + private static void SetDefaultGraphicsAPIs() + { + VRC.Core.Logger.Log("Setting Graphics APIs", VRC.Core.DebugLevel.All); + foreach(BuildTarget target in relevantBuildTargets) + { + GraphicsDeviceType[] apis = allowedGraphicsAPIs[target]; + if(apis == null) + { + SetGraphicsAPIs(target, true); + } + else + { + SetGraphicsAPIs(target, false, apis); + } + } + } + + private static void SetGraphicsAPIs(BuildTarget platform, bool auto, GraphicsDeviceType[] allowedTypes = null) + { + try + { + if(auto != PlayerSettings.GetUseDefaultGraphicsAPIs(platform)) + { + PlayerSettings.SetUseDefaultGraphicsAPIs(platform, auto); + } + } + catch + { + // ignored + } + + try + { + if(allowedTypes == null || allowedTypes.Length == 0) + { + return; + } + + GraphicsDeviceType[] graphicsAPIs = PlayerSettings.GetGraphicsAPIs(platform); + if(graphicsAPIs == null || graphicsAPIs.Length == 0) + { + return; + } + + if(allowedTypes.SequenceEqual(graphicsAPIs)) + { + return; + } + + PlayerSettings.SetGraphicsAPIs(platform, allowedTypes); + } + catch + { + // ignored + } + } + + private static void SetQualitySettings() + { + VRC.Core.Logger.Log("Setting Graphics Settings", VRC.Core.DebugLevel.All); + const string qualitySettingsAssetPath = "ProjectSettings/QualitySettings.asset"; + SerializedObject qualitySettings = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath(qualitySettingsAssetPath)[0]); + + SerializedProperty qualitySettingsPresets = qualitySettings.FindProperty("m_QualitySettings"); + qualitySettingsPresets.arraySize = _graphicsPresets.Length; + + bool changedProperty = false; + for(int index = 0; index < _graphicsPresets.Length; index++) + { + SerializedProperty currentQualityLevel = qualitySettingsPresets.GetArrayElementAtIndex(index); + Dictionary<string, object> graphicsPreset = _graphicsPresets[index]; + foreach(KeyValuePair<string, object> setting in graphicsPreset) + { + SerializedProperty property = currentQualityLevel.FindPropertyRelative(setting.Key); + if(property == null) + { + Debug.LogWarning($"Serialized property for quality setting '{setting.Key}' could not be found."); + continue; + } + + object settingValue = setting.Value; + #if !VRC_CLIENT + if(setting.Key == "name") + { + settingValue = $"VRC {setting.Value}"; + } + #endif + + switch(settingValue) + { + case null: + { + if(property.objectReferenceValue == setting.Value as Object) + { + continue; + } + + property.objectReferenceValue = null; + break; + } + case string settingAsString: + { + if(property.stringValue == settingAsString) + { + continue; + } + + property.stringValue = settingAsString; + break; + } + case bool settingAsBool: + { + if(property.boolValue == settingAsBool) + { + continue; + } + + property.boolValue = settingAsBool; + break; + } + case int settingAsInt: + { + if(property.intValue == settingAsInt) + { + continue; + } + + property.intValue = settingAsInt; + break; + } + case float settingAsFloat: + { + if(Mathf.Approximately(property.floatValue, settingAsFloat)) + { + continue; + } + + property.floatValue = settingAsFloat; + break; + } + case double settingAsDouble: + { + if(Mathf.Approximately((float)property.doubleValue, (float)settingAsDouble)) + { + continue; + } + + property.doubleValue = settingAsDouble; + break; + } + case Vector3 settingAsVector3: + { + if(property.vector3Value == settingAsVector3) + { + continue; + } + + property.vector3Value = settingAsVector3; + break; + } + case string[] settingAsStringArray: + { + property.arraySize = settingAsStringArray.Length; + + bool changedArrayEntry = false; + for(int settingIndex = 0; settingIndex < settingAsStringArray.Length; settingIndex++) + { + SerializedProperty entry = property.GetArrayElementAtIndex(settingIndex); + if(entry.stringValue == settingAsStringArray[settingIndex]) + { + continue; + } + + entry.stringValue = settingAsStringArray[settingIndex]; + changedArrayEntry = true; + } + + if(!changedArrayEntry) + { + continue; + } + + break; + } + } + + #if !VRC_CLIENT + string levelName = _graphicsPresets[index]["name"] as string; + if(Application.isMobilePlatform) + { + if(levelName == "Mobile") + { + Debug.Log($"Set incorrect quality setting '{setting.Key}' in level '{levelName}' to value '{setting.Value}'."); + } + } + else + { + if(levelName != "Mobile") + { + Debug.Log($"Set incorrect quality setting '{setting.Key}' in level '{levelName}' to value '{setting.Value}'."); + } + } + + #endif + changedProperty = true; + } + } + + if(!changedProperty) + { + return; + } + + int defaultQuality = !Application.isMobilePlatform ? 3 : 4; + #if !VRC_CLIENT + Debug.Log($"A quality setting was changed resetting to the default quality: {_graphicsPresets[defaultQuality]["name"]}."); + #endif + SerializedProperty currentGraphicsQuality = qualitySettings.FindProperty("m_CurrentQuality"); + currentGraphicsQuality.intValue = defaultQuality; + + qualitySettings.ApplyModifiedPropertiesWithoutUndo(); + AssetDatabase.SaveAssets(); + } + + private static void SetGraphicsSettings() + { + VRC.Core.Logger.Log("Setting Graphics Settings", VRC.Core.DebugLevel.All); + + const string graphicsSettingsAssetPath = "ProjectSettings/GraphicsSettings.asset"; + SerializedObject graphicsManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath(graphicsSettingsAssetPath)[0]); + + SerializedProperty deferred = graphicsManager.FindProperty("m_Deferred.m_Mode"); + deferred.enumValueIndex = 1; + + SerializedProperty deferredReflections = graphicsManager.FindProperty("m_DeferredReflections.m_Mode"); + deferredReflections.enumValueIndex = 1; + + SerializedProperty screenSpaceShadows = graphicsManager.FindProperty("m_ScreenSpaceShadows.m_Mode"); + screenSpaceShadows.enumValueIndex = 1; + + SerializedProperty legacyDeferred = graphicsManager.FindProperty("m_LegacyDeferred.m_Mode"); + legacyDeferred.enumValueIndex = 1; + + SerializedProperty depthNormals = graphicsManager.FindProperty("m_DepthNormals.m_Mode"); + depthNormals.enumValueIndex = 1; + + SerializedProperty motionVectors = graphicsManager.FindProperty("m_MotionVectors.m_Mode"); + motionVectors.enumValueIndex = 1; + + SerializedProperty lightHalo = graphicsManager.FindProperty("m_LightHalo.m_Mode"); + lightHalo.enumValueIndex = 1; + + SerializedProperty lensFlare = graphicsManager.FindProperty("m_LensFlare.m_Mode"); + lensFlare.enumValueIndex = 1; + + #if ENV_SET_INCLUDED_SHADERS && VRC_CLIENT + // clear GraphicsSettings->Always Included Shaders - these cause a +5s app startup time increase on Quest. + // include Shader objects as resources instead + SerializedProperty alwaysIncluded = graphicsManager.FindProperty("m_AlwaysIncludedShaders"); + alwaysIncluded.arraySize = 0; + + #if ENV_SEARCH_FOR_SHADERS + Resources.LoadAll("", typeof(Shader)); + System.Collections.Generic.List<Shader> foundShaders = Resources.FindObjectsOfTypeAll<Shader>() + .Where(s => { string name = s.name.ToLower(); return 0 == (s.hideFlags & HideFlags.DontSave); }) + .GroupBy(s => s.name) + .Select(g => g.First()) + .ToList(); + #else + List<Shader> foundShaders = new List<Shader>(); + #endif + + foreach(string shader in ensureTheseShadersAreAvailable.OrderBy(s => s, StringComparer.Ordinal)) + { + if(foundShaders.Any(s => s.name == shader)) + { + continue; + } + + Shader namedShader = Shader.Find(shader); + if(namedShader != null) + { + foundShaders.Add(namedShader); + } + } + + foundShaders.Sort((s1, s2) => string.Compare(s1.name, s2.name, StringComparison.Ordinal)); + + // populate Resources list of "always included shaders" + ShaderAssetList alwaysIncludedShaders = AssetDatabase.LoadAssetAtPath<ShaderAssetList>("Assets/Resources/AlwaysIncludedShaders.asset"); + alwaysIncludedShaders.Shaders = new Shader[foundShaders.Count]; + for(int shaderIdx = 0; shaderIdx < foundShaders.Count; ++shaderIdx) + { + alwaysIncludedShaders.Shaders[shaderIdx] = foundShaders[shaderIdx]; + } + + EditorUtility.SetDirty(alwaysIncludedShaders); + #endif + + SerializedProperty preloaded = graphicsManager.FindProperty("m_PreloadedShaders"); + preloaded.ClearArray(); + preloaded.arraySize = 0; + + SerializedProperty spritesDefaultMaterial = graphicsManager.FindProperty("m_SpritesDefaultMaterial"); + spritesDefaultMaterial.objectReferenceValue = Shader.Find("Sprites/Default"); + + SerializedProperty renderPipeline = graphicsManager.FindProperty("m_CustomRenderPipeline"); + renderPipeline.objectReferenceValue = null; + + SerializedProperty transparencySortMode = graphicsManager.FindProperty("m_TransparencySortMode"); + transparencySortMode.enumValueIndex = 0; + + SerializedProperty transparencySortAxis = graphicsManager.FindProperty("m_TransparencySortAxis"); + transparencySortAxis.vector3Value = Vector3.forward; + + SerializedProperty defaultRenderingPath = graphicsManager.FindProperty("m_DefaultRenderingPath"); + defaultRenderingPath.intValue = 1; + + SerializedProperty defaultMobileRenderingPath = graphicsManager.FindProperty("m_DefaultMobileRenderingPath"); + defaultMobileRenderingPath.intValue = 1; + + SerializedProperty tierSettings = graphicsManager.FindProperty("m_TierSettings"); + tierSettings.ClearArray(); + tierSettings.arraySize = 0; + + #if ENV_SET_LIGHTMAP + SerializedProperty lightmapStripping = graphicsManager.FindProperty("m_LightmapStripping"); + lightmapStripping.enumValueIndex = 1; + + SerializedProperty instancingStripping = graphicsManager.FindProperty("m_InstancingStripping"); + instancingStripping.enumValueIndex = 2; + + SerializedProperty lightmapKeepPlain = graphicsManager.FindProperty("m_LightmapKeepPlain"); + lightmapKeepPlain.boolValue = true; + + SerializedProperty lightmapKeepDirCombined = graphicsManager.FindProperty("m_LightmapKeepDirCombined"); + lightmapKeepDirCombined.boolValue = true; + + SerializedProperty lightmapKeepDynamicPlain = graphicsManager.FindProperty("m_LightmapKeepDynamicPlain"); + lightmapKeepDynamicPlain.boolValue = true; + + SerializedProperty lightmapKeepDynamicDirCombined = graphicsManager.FindProperty("m_LightmapKeepDynamicDirCombined"); + lightmapKeepDynamicDirCombined.boolValue = true; + + SerializedProperty lightmapKeepShadowMask = graphicsManager.FindProperty("m_LightmapKeepShadowMask"); + lightmapKeepShadowMask.boolValue = true; + + SerializedProperty lightmapKeepSubtractive = graphicsManager.FindProperty("m_LightmapKeepSubtractive"); + lightmapKeepSubtractive.boolValue = true; + #endif + + SerializedProperty albedoSwatchInfos = graphicsManager.FindProperty("m_AlbedoSwatchInfos"); + albedoSwatchInfos.ClearArray(); + albedoSwatchInfos.arraySize = 0; + + SerializedProperty lightsUseLinearIntensity = graphicsManager.FindProperty("m_LightsUseLinearIntensity"); + lightsUseLinearIntensity.boolValue = true; + + SerializedProperty lightsUseColorTemperature = graphicsManager.FindProperty("m_LightsUseColorTemperature"); + lightsUseColorTemperature.boolValue = true; + + graphicsManager.ApplyModifiedProperties(); + } + + public static FogSettings GetFogSettings() + { + VRC.Core.Logger.Log("Force-enabling Fog", VRC.Core.DebugLevel.All); + + const string graphicsSettingsAssetPath = "ProjectSettings/GraphicsSettings.asset"; + SerializedObject graphicsManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath(graphicsSettingsAssetPath)[0]); + + + SerializedProperty fogStrippingSerializedProperty = graphicsManager.FindProperty("m_FogStripping"); + FogSettings.FogStrippingMode fogStripping = (FogSettings.FogStrippingMode)fogStrippingSerializedProperty.enumValueIndex; + + SerializedProperty fogKeepLinearSerializedProperty = graphicsManager.FindProperty("m_FogKeepLinear"); + bool keepLinear = fogKeepLinearSerializedProperty.boolValue; + + SerializedProperty fogKeepExpSerializedProperty = graphicsManager.FindProperty("m_FogKeepExp"); + bool keepExp = fogKeepExpSerializedProperty.boolValue; + + SerializedProperty fogKeepExp2SerializedProperty = graphicsManager.FindProperty("m_FogKeepExp2"); + bool keepExp2 = fogKeepExp2SerializedProperty.boolValue; + + FogSettings fogSettings = new FogSettings(fogStripping, keepLinear, keepExp, keepExp2); + return fogSettings; + } + + public static void SetFogSettings(FogSettings fogSettings) + { + VRC.Core.Logger.Log("Force-enabling Fog", VRC.Core.DebugLevel.All); + + const string graphicsSettingsAssetPath = "ProjectSettings/GraphicsSettings.asset"; + SerializedObject graphicsManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath(graphicsSettingsAssetPath)[0]); + + SerializedProperty fogStripping = graphicsManager.FindProperty("m_FogStripping"); + fogStripping.enumValueIndex = (int)fogSettings.fogStrippingMode; + + SerializedProperty fogKeepLinear = graphicsManager.FindProperty("m_FogKeepLinear"); + fogKeepLinear.boolValue = fogSettings.keepLinear; + + SerializedProperty fogKeepExp = graphicsManager.FindProperty("m_FogKeepExp"); + fogKeepExp.boolValue = fogSettings.keepExp; + + SerializedProperty fogKeepExp2 = graphicsManager.FindProperty("m_FogKeepExp2"); + fogKeepExp2.boolValue = fogSettings.keepExp2; + + graphicsManager.ApplyModifiedProperties(); + } + + private static void SetAudioSettings() + { + Object audioManager = AssetDatabase.LoadMainAssetAtPath("ProjectSettings/AudioManager.asset"); + SerializedObject audioManagerSerializedObject = new SerializedObject(audioManager); + audioManagerSerializedObject.Update(); + + SerializedProperty sampleRateSerializedProperty = audioManagerSerializedObject.FindProperty("m_SampleRate"); + sampleRateSerializedProperty.intValue = 48000; // forcing 48k seems to avoid sample rate conversion problems + + SerializedProperty dspBufferSizeSerializedProperty = audioManagerSerializedObject.FindProperty("m_RequestedDSPBufferSize"); + dspBufferSizeSerializedProperty.intValue = 0; + + SerializedProperty defaultSpeakerModeSerializedProperty = audioManagerSerializedObject.FindProperty("Default Speaker Mode"); + defaultSpeakerModeSerializedProperty.intValue = 2; // 2 = Stereo + + SerializedProperty virtualVoiceCountSerializedProperty = audioManagerSerializedObject.FindProperty("m_VirtualVoiceCount"); + SerializedProperty realVoiceCountSerializedProperty = audioManagerSerializedObject.FindProperty("m_RealVoiceCount"); + if(EditorUserBuildSettings.selectedBuildTargetGroup == BuildTargetGroup.Android) + { + virtualVoiceCountSerializedProperty.intValue = 32; + realVoiceCountSerializedProperty.intValue = 24; + } + else + { + virtualVoiceCountSerializedProperty.intValue = 64; + realVoiceCountSerializedProperty.intValue = 32; + } + + audioManagerSerializedObject.ApplyModifiedPropertiesWithoutUndo(); + AssetDatabase.SaveAssets(); + } + + private static void SetPlayerSettings() + { + // asset bundles MUST be built with settings that are compatible with VRC client + #if VRC_OVERRIDE_COLORSPACE_GAMMA + PlayerSettings.colorSpace = ColorSpace.Gamma; + #else + PlayerSettings.colorSpace = ColorSpace.Linear; + #endif + + #if !VRC_CLIENT // In client rely on platform-switcher + if (!EditorApplication.isPlaying) + { + #pragma warning disable 618 + PlayerSettings.SetVirtualRealitySupported(EditorUserBuildSettings.selectedBuildTargetGroup, true); + #pragma warning restore 618 + } + #endif + + PlayerSettings.graphicsJobs = true; + + PlayerSettings.gpuSkinning = true; + + #if UNITY_2019_3_OR_NEWER + PlayerSettings.gcIncremental = true; + #endif + +#if VRC_VR_WAVE + PlayerSettings.stereoRenderingPath = StereoRenderingPath.MultiPass; // Need to use Multi-pass on Wave SDK otherwise mirrors break +#else + PlayerSettings.stereoRenderingPath = StereoRenderingPath.SinglePass; +#endif + +#if UNITY_2018_4_OR_NEWER && !UNITY_2019_3_OR_NEWER + PlayerSettings.scriptingRuntimeVersion = ScriptingRuntimeVersion.Latest; +#endif + +#if UNITY_ANDROID + PlayerSettings.Android.forceSDCardPermission = true; // Need access to SD card for saving images + PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARM64; + + if(PlayerSettings.Android.targetArchitectures.HasFlag(AndroidArchitecture.ARM64)) + { + // Since we need different IL2CPP args we can't build ARM64 with other Architectures. + PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARM64; + PlayerSettings.SetAdditionalIl2CppArgs(""); + } + else + { + PlayerSettings.SetAdditionalIl2CppArgs("--linker-flags=\"-long-plt\""); + } + + #if UNITY_2019_3_OR_NEWER + PlayerSettings.Android.targetSdkVersion = AndroidSdkVersions.AndroidApiLevel29; + #else + PlayerSettings.Android.targetSdkVersion = AndroidSdkVersions.AndroidApiLevel26; + #endif +#else + PlayerSettings.SetAdditionalIl2CppArgs(""); +#endif + + SetActiveSDKDefines(); + + EnableBatching(true); + } + + public static void SetActiveSDKDefines() + { + bool definesChanged = false; + BuildTargetGroup buildTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget); + List<string> defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup).Split(';').ToList(); + + Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); + if(assemblies.Any(assembly => assembly.GetType("VRC.Udon.UdonBehaviour") != null)) + { + if(!defines.Contains("UDON", StringComparer.OrdinalIgnoreCase)) + { + defines.Add("UDON"); + definesChanged = true; + } + } + else if(defines.Contains("UDON")) + { + defines.Remove("UDON"); + } + + if(VRCSdk3Analysis.IsSdkDllActive(VRCSdk3Analysis.SdkVersion.VRCSDK2)) + { + if(!defines.Contains("VRC_SDK_VRCSDK2", StringComparer.OrdinalIgnoreCase)) + { + defines.Add("VRC_SDK_VRCSDK2"); + definesChanged = true; + } + } + else if(defines.Contains("VRC_SDK_VRCSDK2")) + { + defines.Remove("VRC_SDK_VRCSDK2"); + } + + if(VRCSdk3Analysis.IsSdkDllActive(VRCSdk3Analysis.SdkVersion.VRCSDK3)) + { + if(!defines.Contains("VRC_SDK_VRCSDK3", StringComparer.OrdinalIgnoreCase)) + { + defines.Add("VRC_SDK_VRCSDK3"); + definesChanged = true; + } + } + else if(defines.Contains("VRC_SDK_VRCSDK3")) + { + defines.Remove("VRC_SDK_VRCSDK3"); + } + + if(definesChanged) + { + PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, string.Join(";", defines.ToArray())); + } + } + + private static void SetBuildTarget() + { + #if !VRC_CLIENT + VRC.Core.Logger.Log("Setting build target", VRC.Core.DebugLevel.All); + + BuildTarget target = UnityEditor.EditorUserBuildSettings.activeBuildTarget; + + if (!allowedBuildtargets.Contains(target)) + { + Debug.LogError("Target not supported, switching to one that is."); + target = allowedBuildtargets[0]; + #pragma warning disable CS0618 // Type or member is obsolete + EditorUserBuildSettings.SwitchActiveBuildTarget(target); + #pragma warning restore CS0618 // Type or member is obsolete + } + #endif + } + + private static void ConfigureAssets() + { +#if VRC_CLIENT + VRC.UI.Client.Editor.VRCUIManagerEditorHelpers.ConfigureNewUIAssets(); +#endif + } + + private static void LoadEditorResources() + { + AvatarPerformanceStats.Initialize(); + } + + public readonly struct FogSettings + { + public enum FogStrippingMode + { + Automatic, + Custom + } + + public readonly FogStrippingMode fogStrippingMode; + public readonly bool keepLinear; + public readonly bool keepExp; + public readonly bool keepExp2; + + public FogSettings(FogStrippingMode fogStrippingMode) + { + this.fogStrippingMode = fogStrippingMode; + keepLinear = true; + keepExp = true; + keepExp2 = true; + } + + public FogSettings(FogStrippingMode fogStrippingMode, bool keepLinear, bool keepExp, bool keepExp2) + { + this.fogStrippingMode = fogStrippingMode; + this.keepLinear = keepLinear; + this.keepExp = keepExp; + this.keepExp2 = keepExp2; + } + } + + private static readonly Dictionary<string, object>[] _graphicsPresets = { + new Dictionary<string, object> + { + {"name", "Low"}, + {"pixelLightCount", 4}, + {"shadows", 2}, + {"shadowResolution", 2}, + {"shadowProjection", 1}, + {"shadowCascades", 2}, + {"shadowDistance", 75f}, + {"shadowNearPlaneOffset", 2f}, + {"shadowCascade2Split", 0.33333334}, + {"shadowCascade4Split", new Vector3(0.06666667f, 0.19999999f, 0.46666664f)}, + {"shadowmaskMode", 0}, + {"skinWeights", 4}, + {"textureQuality", 0}, + {"anisotropicTextures", 2}, + {"antiAliasing", 0}, + {"softParticles", true}, + {"softVegetation", true}, + {"realtimeReflectionProbes", true}, + {"billboardsFaceCameraPosition", true}, + {"vSyncCount", 0}, + {"lodBias", 1f}, + {"maximumLODLevel", 0}, + {"streamingMipmapsActive", false}, + {"streamingMipmapsAddAllCameras", true}, + {"streamingMipmapsMemoryBudget", 512f}, + {"streamingMipmapsRenderersPerFrame", 512}, + {"streamingMipmapsMaxLevelReduction", 2}, + {"streamingMipmapsMaxFileIORequests", 1024}, + {"particleRaycastBudget", 1024}, + {"asyncUploadTimeSlice", 2}, + {"asyncUploadBufferSize", 64}, + {"asyncUploadPersistentBuffer", true}, + {"resolutionScalingFixedDPIFactor", 1f}, + {"customRenderPipeline", null}, + {"excludedTargetPlatforms", new[] {"Android"}} + }, + new Dictionary<string, object> + { + {"name", "Medium"}, + {"pixelLightCount", 4}, + {"shadows", 2}, + {"shadowResolution", 2}, + {"shadowProjection", 1}, + {"shadowCascades", 2}, + {"shadowDistance", 75f}, + {"shadowNearPlaneOffset", 2f}, + {"shadowCascade2Split", 0.33333334}, + {"shadowCascade4Split", new Vector3(0.06666667f, 0.19999999f, 0.46666664f)}, + {"shadowmaskMode", 0}, + {"skinWeights", 4}, + {"textureQuality", 0}, + {"anisotropicTextures", 2}, + {"antiAliasing", 4}, + {"softParticles", true}, + {"softVegetation", true}, + {"realtimeReflectionProbes", true}, + {"billboardsFaceCameraPosition", true}, + {"vSyncCount", 0}, + {"lodBias", 1.5f}, + {"maximumLODLevel", 0}, + {"streamingMipmapsActive", false}, + {"streamingMipmapsAddAllCameras", true}, + {"streamingMipmapsMemoryBudget", 512f}, + {"streamingMipmapsRenderersPerFrame", 512}, + {"streamingMipmapsMaxLevelReduction", 2}, + {"streamingMipmapsMaxFileIORequests", 1024}, + {"particleRaycastBudget", 2048}, + {"asyncUploadTimeSlice", 2}, + {"asyncUploadBufferSize", 64}, + {"asyncUploadPersistentBuffer", true}, + {"resolutionScalingFixedDPIFactor", 1f}, + {"customRenderPipeline", null}, + {"excludedTargetPlatforms", new[] {"Android"}} + }, + new Dictionary<string, object> + { + {"name", "High"}, + {"pixelLightCount", 8}, + {"shadows", 2}, + {"shadowResolution", 3}, + {"shadowProjection", 1}, + {"shadowCascades", 2}, + {"shadowDistance", 75f}, + {"shadowNearPlaneOffset", 2f}, + {"shadowCascade2Split", 0.33333334}, + {"shadowCascade4Split", new Vector3(0.06666667f, 0.19999999f, 0.46666664f)}, + {"shadowmaskMode", 0}, + {"skinWeights", 4}, + {"textureQuality", 0}, + {"anisotropicTextures", 2}, + {"antiAliasing", 4}, + {"softParticles", true}, + {"softVegetation", true}, + {"realtimeReflectionProbes", true}, + {"billboardsFaceCameraPosition", true}, + {"vSyncCount", 0}, + {"lodBias", 2f}, + {"maximumLODLevel", 0}, + {"streamingMipmapsActive", false}, + {"streamingMipmapsAddAllCameras", true}, + {"streamingMipmapsMemoryBudget", 512f}, + {"streamingMipmapsRenderersPerFrame", 512}, + {"streamingMipmapsMaxLevelReduction", 2}, + {"streamingMipmapsMaxFileIORequests", 1024}, + {"particleRaycastBudget", 4096}, + {"asyncUploadTimeSlice", 2}, + {"asyncUploadBufferSize", 128}, + {"asyncUploadPersistentBuffer", true}, + {"resolutionScalingFixedDPIFactor", 1f}, + {"customRenderPipeline", null}, + {"excludedTargetPlatforms", new []{"Android"}} + }, + new Dictionary<string, object> + { + {"name", "Ultra"}, + {"pixelLightCount", 8}, + {"shadows", 2}, + {"shadowResolution", 3}, + {"shadowProjection", 1}, + {"shadowCascades", 4}, + {"shadowDistance", 150f}, + {"shadowNearPlaneOffset", 2f}, + {"shadowCascade2Split", 0.33333334}, + {"shadowCascade4Split", new Vector3(0.06666667f, 0.19999999f, 0.46666664f)}, + {"shadowmaskMode", 0}, + {"skinWeights", 4}, + {"textureQuality", 0}, + {"anisotropicTextures", 2}, + {"antiAliasing", 4}, + {"softParticles", true}, + {"softVegetation", true}, + {"realtimeReflectionProbes", true}, + {"billboardsFaceCameraPosition", true}, + {"vSyncCount", 0}, + {"lodBias", 2f}, + {"maximumLODLevel", 0}, + {"streamingMipmapsActive", false}, + {"streamingMipmapsAddAllCameras", true}, + {"streamingMipmapsMemoryBudget", 512f}, + {"streamingMipmapsRenderersPerFrame", 512}, + {"streamingMipmapsMaxLevelReduction", 2}, + {"streamingMipmapsMaxFileIORequests", 1024}, + {"particleRaycastBudget", 4096}, + {"asyncUploadTimeSlice", 2}, + {"asyncUploadBufferSize", 128}, + {"asyncUploadPersistentBuffer", true}, + {"resolutionScalingFixedDPIFactor", 1f}, + {"customRenderPipeline", null}, + {"excludedTargetPlatforms", new[]{"Android"}} + }, + new Dictionary<string, object> + { + {"name", "Mobile"}, + {"pixelLightCount", 4}, + {"shadows", 0}, + {"shadowResolution", 1}, + {"shadowProjection", 1}, + {"shadowCascades", 1}, + {"shadowDistance", 50f}, + {"shadowNearPlaneOffset", 2f}, + {"shadowCascade2Split", 0.33333334}, + {"shadowCascade4Split", new Vector3(0.06666667f, 0.19999999f, 0.46666664f)}, + {"shadowmaskMode", 0}, + {"skinWeights", 4}, + {"textureQuality", 0}, + {"anisotropicTextures", 2}, + {"antiAliasing", 2}, + {"softParticles", false}, + {"softVegetation", false}, + {"realtimeReflectionProbes", false}, + {"billboardsFaceCameraPosition", true}, + {"vSyncCount", 0}, + {"lodBias", 2f}, + {"maximumLODLevel", 0}, + {"streamingMipmapsActive", false}, + {"streamingMipmapsAddAllCameras", true}, + {"streamingMipmapsMemoryBudget", 512f}, + {"streamingMipmapsRenderersPerFrame", 512}, + {"streamingMipmapsMaxLevelReduction", 2}, + {"streamingMipmapsMaxFileIORequests", 1024}, + {"particleRaycastBudget", 1024}, + {"asyncUploadTimeSlice", 1}, + {"asyncUploadBufferSize", 32}, + {"asyncUploadPersistentBuffer", true}, + {"resolutionScalingFixedDPIFactor", 1f}, + {"customRenderPipeline", null}, + {"excludedTargetPlatforms", new []{"Standalone"}} + } + }; +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/EnvConfig.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/EnvConfig.cs.meta new file mode 100644 index 00000000..9e0353a3 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/EnvConfig.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 10d9f721d76e07a47bc9e5f61e2fae72 +timeCreated: 1455115256 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/FixAnimatorControllers.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/FixAnimatorControllers.cs new file mode 100644 index 00000000..d3459907 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/FixAnimatorControllers.cs @@ -0,0 +1,88 @@ +// This code was adapted from: https://github.com/Joshuarox100/Fix-Your-Animators/blob/main/FixYourAnimators.cs +// MIT License +// +// Copyright (c) 2021 Joshuarox100 +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +using System; +using System.Collections.Generic; +using UnityEditor; +using UnityEditor.Animations; +using UnityEngine; + +namespace VRC.SDKBase.Editor +{ + public static class FixAnimatorControllers + { + private static readonly HashSet<Type> types = new HashSet<Type> + { + typeof(AnimatorState), + typeof(AnimatorStateMachine), + typeof(StateMachineBehaviour), + typeof(AnimatorStateTransition), + typeof(AnimatorTransition), + typeof(BlendTree) + }; + + [InitializeOnLoadMethod] + private static void RegisterDelegates() + { + Selection.selectionChanged += AutoFixHideFlags; + EditorApplication.quitting += UnregisterDelegates; + } + + public static void UnregisterDelegates() + { + Selection.selectionChanged -= AutoFixHideFlags; + EditorApplication.quitting -= UnregisterDelegates; + } + + // Automatically corrects HideFlags for objects with types included in 'types' when trying to inspect them. + public static void AutoFixHideFlags() + { + bool dirty = false; + foreach(UnityEngine.Object selection in Selection.objects) + { + if(selection == null) + { + continue; + } + + if(selection.hideFlags != (HideFlags.HideInHierarchy | HideFlags.HideInInspector) || !types.Contains(selection.GetType())) + { + continue; + } + + if(!string.IsNullOrEmpty(AssetDatabase.GetAssetPath(selection))) + { + EditorUtility.SetDirty(selection); + } + + selection.hideFlags = HideFlags.HideInHierarchy; + dirty = true; + } + + if(dirty) + { + Selection.selectionChanged(); + } + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/FixAnimatorControllers.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/FixAnimatorControllers.cs.meta new file mode 100644 index 00000000..053757cf --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/FixAnimatorControllers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0bc1f4d12c7c0f3468bd3469a5209dc1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/FixConstraintUpdateOrder.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/FixConstraintUpdateOrder.cs new file mode 100644 index 00000000..6735702b --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/FixConstraintUpdateOrder.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.LowLevel; +using UnityEngine.PlayerLoop; + +namespace VRC.SDKBase.Editor +{ +#if !VRC_CLIENT + public static class FixConstraintUpdateOrder + { + [RuntimeInitializeOnLoadMethod] + private static void ApplyFix() + { + PlayerLoopSystem currentPlayerLoopSystem = PlayerLoop.GetCurrentPlayerLoop(); + + // Search the current PlayerLoopSystem's sub-systems for the PreLateUpdate system. + PlayerLoopSystem[] playerLoopSystems = currentPlayerLoopSystem.subSystemList; + int preLateUpdateSystemIndex = Array.FindIndex(playerLoopSystems, system => system.type == typeof(PreLateUpdate)); + PlayerLoopSystem preLateUpdateSystem = playerLoopSystems[preLateUpdateSystemIndex]; + + // Search the PreLateUpdate system's sub-systems for ScriptRunBehaviourLateUpdate and ConstraintManagerUpdate. + List<PlayerLoopSystem> preLateUpdateSystemSubSystems = preLateUpdateSystem.subSystemList.ToList(); + PlayerLoopSystem scriptRunBehaviourLateUpdateSystem = preLateUpdateSystemSubSystems.Find(system => system.type == typeof(PreLateUpdate.ScriptRunBehaviourLateUpdate)); + PlayerLoopSystem constraintManagerUpdateSystem = preLateUpdateSystemSubSystems.Find(system => system.type == typeof(PreLateUpdate.ConstraintManagerUpdate)); + + // Move ScriptRunBehaviourLateUpdate to before ConstraintManagerUpdate. + preLateUpdateSystemSubSystems.Remove(scriptRunBehaviourLateUpdateSystem); + preLateUpdateSystemSubSystems.Insert(preLateUpdateSystemSubSystems.IndexOf(constraintManagerUpdateSystem), scriptRunBehaviourLateUpdateSystem); + + // Update the PlayerLoopSystem structs. + preLateUpdateSystem.subSystemList = preLateUpdateSystemSubSystems.ToArray(); + playerLoopSystems[preLateUpdateSystemIndex] = preLateUpdateSystem; + currentPlayerLoopSystem.subSystemList = playerLoopSystems; + PlayerLoop.SetPlayerLoop(currentPlayerLoopSystem); + } + } +#endif +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/FixConstraintUpdateOrder.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/FixConstraintUpdateOrder.cs.meta new file mode 100644 index 00000000..c5d7fc6b --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/FixConstraintUpdateOrder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9a4af4545014b16439e24fcba1fd1e5e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/HDRColorFixerUtility.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/HDRColorFixerUtility.cs new file mode 100644 index 00000000..a7ea788f --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/HDRColorFixerUtility.cs @@ -0,0 +1,73 @@ +using UnityEditor; +using UnityEngine; + +public static class HDRColorFixerUtility +{ + [MenuItem("VRChat SDK/Utilities/Convert HDR Material Colors/To Linear", false, 995)] + private static void ConvertToLinear() + { + if (!TryConvert()) + EditorUtility.DisplayDialog("Error", "Please select one or more HDR materials to convert.", "OK"); + } + + [MenuItem("VRChat SDK/Utilities/Convert HDR Material Colors/To Gamma", false, 996)] + private static void ConvertToGamma() + { + if (!TryConvert(false)) + EditorUtility.DisplayDialog("Error", "Please select one or more HDR materials to convert.", "OK"); + } + + static bool TryConvert(bool toLinear = true) + { + Object[] selection = Selection.objects; + if (selection == null) + return false; + + int matCount = 0; + int colorCount = 0; + foreach (Material mat in selection) + { + matCount++; + MaterialProperty[] props = MaterialEditor.GetMaterialProperties(new Material[] { mat }); + if ((props == null) || (props.Length == 0)) + return false; + + foreach (MaterialProperty m in props) + { + if (m.flags == MaterialProperty.PropFlags.HDR) + { + //Color prev = m.colorValue; + m.colorValue = (toLinear ? m.colorValue.linear : m.colorValue.gamma); + colorCount++; + //Debug.Log("prev: " + prev + ", current: " + m.colorValue); + } + } + } + + if (colorCount == 0) + EditorUtility.DisplayDialog("Result", "Found no HDR Color properties in the selected material" + (matCount > 1 ? "s." : "."), "OK"); + else + EditorUtility.DisplayDialog("Result", "Converted " + colorCount + " HDR Color propert"+ (colorCount > 1 ? "ies" : "y") + " in "+matCount+" material"+(matCount > 1 ? "s":"") + " to " + (toLinear ? "Linear" : "Gamma") + " color space.", "OK"); + + return true; + } + + [MenuItem("VRChat SDK/Utilities/Convert HDR Material Colors/To Linear", true, 995)] + [MenuItem("VRChat SDK/Utilities/Convert HDR Material Colors/To Gamma", true, 996)] + private static bool CheckSelection() + { + if (Selection.objects.Length == 0) + return false; + bool allMaterials = true; + foreach (Object obj in Selection.objects) + { + if (obj.GetType() != typeof(Material)) + { + allMaterials = false; + break; + } + } + return allMaterials; + } + +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/HDRColorFixerUtility.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/HDRColorFixerUtility.cs.meta new file mode 100644 index 00000000..b3ff9fe0 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/HDRColorFixerUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c3399613f583f3e46b2df27ae87dd5d6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources.meta new file mode 100644 index 00000000..8373c2a8 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 499413fa282e39149b6a459738bc015d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/SDK_Panel_Banner.png b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/SDK_Panel_Banner.png Binary files differnew file mode 100644 index 00000000..c42cc3f1 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/SDK_Panel_Banner.png diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/SDK_Panel_Banner.png.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/SDK_Panel_Banner.png.meta new file mode 100644 index 00000000..f70de059 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/SDK_Panel_Banner.png.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: 9ae7399f0cf902a41a20f3487af8322a +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: -1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 0 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5772d417389f8c34cb882113498aee62 + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkBottomHeader.png b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkBottomHeader.png Binary files differnew file mode 100644 index 00000000..a0a529d1 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkBottomHeader.png diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkBottomHeader.png.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkBottomHeader.png.meta new file mode 100644 index 00000000..d20a5fc1 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkBottomHeader.png.meta @@ -0,0 +1,86 @@ +fileFormatVersion: 2 +guid: 8c4423c989a97d64eabbd9375dbd3e89 +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 4 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkClDialogNewIcon.png b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkClDialogNewIcon.png Binary files differnew file mode 100644 index 00000000..aecf1065 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkClDialogNewIcon.png diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkClDialogNewIcon.png.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkClDialogNewIcon.png.meta new file mode 100644 index 00000000..02aef12c --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkClDialogNewIcon.png.meta @@ -0,0 +1,136 @@ +fileFormatVersion: 2 +guid: cb3df6568f1c9b74d8bbe0e192d2514d +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 4 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: tvOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkHeader.png b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkHeader.png Binary files differnew file mode 100644 index 00000000..91d814e2 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkHeader.png diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkHeader.png.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkHeader.png.meta new file mode 100644 index 00000000..9071a85f --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkHeader.png.meta @@ -0,0 +1,84 @@ +fileFormatVersion: 2 +guid: 1fc57198d6a4e5a4e9c3175ab5c609a7 +timeCreated: 1532782887 +licenseType: Pro +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 4 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + - buildTarget: Standalone + maxTextureSize: 2048 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + - buildTarget: Android + maxTextureSize: 2048 + textureFormat: 50 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 1 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkHeaderWithCommunityLabs.png b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkHeaderWithCommunityLabs.png Binary files differnew file mode 100644 index 00000000..a5336880 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkHeaderWithCommunityLabs.png diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkHeaderWithCommunityLabs.png.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkHeaderWithCommunityLabs.png.meta new file mode 100644 index 00000000..df15be5a --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkHeaderWithCommunityLabs.png.meta @@ -0,0 +1,136 @@ +fileFormatVersion: 2 +guid: e244718b600092a4bae1a08e7795305e +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 4 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: tvOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkSplashUdon1.png b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkSplashUdon1.png Binary files differnew file mode 100644 index 00000000..0fe45be0 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkSplashUdon1.png diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkSplashUdon1.png.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkSplashUdon1.png.meta new file mode 100644 index 00000000..90553dec --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkSplashUdon1.png.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: a337b85d7d3b8f0408576d7f08bf609f +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: 1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkSplashUdon2.png b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkSplashUdon2.png Binary files differnew file mode 100644 index 00000000..a4f86a7c --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkSplashUdon2.png diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkSplashUdon2.png.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkSplashUdon2.png.meta new file mode 100644 index 00000000..a7026abf --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Resources/vrcSdkSplashUdon2.png.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: 19889d5e743a45f4da316fb1d760ffba +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: 1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/SDK3Compatibility.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/SDK3Compatibility.meta new file mode 100644 index 00000000..c9ad260f --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/SDK3Compatibility.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2ce6d1e55aa6703419e845d3b54db0bc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/SDK3Compatibility/VRCSdk3Analysis.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/SDK3Compatibility/VRCSdk3Analysis.cs new file mode 100644 index 00000000..ee656b38 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/SDK3Compatibility/VRCSdk3Analysis.cs @@ -0,0 +1,70 @@ +using System.Reflection; +using System.Collections.Generic; +using UnityEngine; +using System; +using System.Linq; +using UnityEditor; + +public class VRCSdk3Analysis +{ + static Assembly GetAssemblyByName(string name) + { + return AppDomain.CurrentDomain.GetAssemblies(). + SingleOrDefault(assembly => assembly.GetName().Name == name); + } + + static List<Component> GetSceneComponentsFromAssembly( Assembly assembly ) + { + if (assembly == null) + return new List<Component>(); + + Type[] types = assembly.GetTypes(); + + List<Component> present = new List<Component>(); + foreach (var type in types ) + { + if (!type.IsSubclassOf(typeof(MonoBehaviour))) + continue; + + var monos = VRC.Tools.FindSceneObjectsOfTypeAll(type); + present.AddRange(monos); + } + return present; + } + + public enum SdkVersion + { + VRCSDK2, + VRCSDK3 + }; + + public static List<Component> GetSDKInScene(SdkVersion version) + { + var assembly = GetAssemblyByName( version.ToString() ); + return GetSceneComponentsFromAssembly(assembly); + } + + public static bool IsSdkDllActive(SdkVersion version) + { + string assembly = version.ToString(); + PluginImporter importer = GetImporterForAssemblyString(assembly); + if (importer == false) + { + //Handle Avatar Dll Split + importer = GetImporterForAssemblyString(assembly + "A"); + if (importer == false) + return false; + } + + return importer.GetCompatibleWithAnyPlatform(); + } + + public static PluginImporter GetImporterForAssemblyString(string assembly) + { +#if VRCUPM + return AssetImporter.GetAtPath($"Packages/com.vrchat.{assembly.ToLower()}/Runtime/VRCSDK/Plugins/{assembly}.dll") as PluginImporter; +#else + return AssetImporter.GetAtPath($"Assets/VRCSDK/Plugins/{assembly}.dll") as PluginImporter; +#endif + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/SDK3Compatibility/VRCSdk3Analysis.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/SDK3Compatibility/VRCSdk3Analysis.cs.meta new file mode 100644 index 00000000..8a2d89cb --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/SDK3Compatibility/VRCSdk3Analysis.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 93710d221addc0243ba90dd20369844b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/SDKUpdater.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/SDKUpdater.cs new file mode 100644 index 00000000..0be3003a --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/SDKUpdater.cs @@ -0,0 +1,70 @@ +using UnityEngine; +using System.Collections; +using UnityEditor; + +public class SDKUpdater : MonoBehaviour +{ + static string GetCurrentVersion() + { + string currentVersion = ""; + string versionTextPath = Application.dataPath + "/VRCSDK/version.txt"; + if(System.IO.File.Exists(versionTextPath)) + { + string[] versionFileLines = System.IO.File.ReadAllLines(versionTextPath); + if(versionFileLines.Length > 0) + currentVersion = versionFileLines[0]; + } + return currentVersion; + } + + [MenuItem("VRChat SDK/Utilities/Check For Updates")] + static void CheckForUpdatesWithProgressBar() + { + CheckForUpdates(false); + } + + public static void CheckForUpdates(bool isSilent = true) + { + Debug.Log("Checking for VRChat SDK updates..."); + if(!isSilent) + EditorUtility.DisplayProgressBar("SDK Updater", "Checking for updates...", 1f); + + VRC.Core.ConfigManager.RemoteConfig.Init(delegate() { + string currentSdkVersion = GetCurrentVersion(); + string sdkVersion = VRC.Core.ConfigManager.RemoteConfig.GetString("devSdkVersion"); + string sdkUrl = VRC.Core.ConfigManager.RemoteConfig.GetString("devSdkUrl"); + EditorUtility.ClearProgressBar(); + + if(sdkVersion == currentSdkVersion) + { + ShowDownloadUpdatePopup(false, currentSdkVersion, sdkUrl, isSilent); + } + else + { + ShowDownloadUpdatePopup(true, sdkVersion, sdkUrl, isSilent); + } + }); + } + + static void ShowDownloadUpdatePopup(bool updateAvailable, string latestVersion, string sdkUrl, bool isSilent) + { + if(!updateAvailable) + { + if(!isSilent) + EditorUtility.DisplayDialog("VRChat SDK Updater", "SDK is up to date (version " + latestVersion + ")", "Okay"); + } + else + { + if(EditorUtility.DisplayDialog("VRChat SDK Updater", "An update is available (version " + latestVersion + ")", "Download", "Cancel")) + { + DownloadUpdate(sdkUrl); + } + } + } + + static void DownloadUpdate(string sdkUrl) + { + Application.OpenURL(sdkUrl); + } + +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/SDKUpdater.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/SDKUpdater.cs.meta new file mode 100644 index 00000000..bb4e950e --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/SDKUpdater.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7b8bb626428d0f341b9ed6a68cb5c9cc +timeCreated: 1473273663 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderKeywordsUtility.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderKeywordsUtility.cs new file mode 100644 index 00000000..84f78700 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderKeywordsUtility.cs @@ -0,0 +1,383 @@ +// Original ShaderKeywordsUtility by ScruffyRules#0879 +// Thank you to Xiexe and all that tested! +// Licensed under the MIT License (see https://vrchat.com/legal/attribution) + +#if UNITY_EDITOR +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using UnityEngine.SceneManagement; + +public class ShaderKeywordsUtility : EditorWindow +{ + private static Dictionary<VRC.SDKBase.VRC_AvatarDescriptor, Dictionary<Material, bool>> avatars = new Dictionary<VRC.SDKBase.VRC_AvatarDescriptor, Dictionary<Material, bool>>(); + private Dictionary<VRC.SDKBase.VRC_AvatarDescriptor, bool> avatarsOpened = new Dictionary<VRC.SDKBase.VRC_AvatarDescriptor, bool>(); + private Vector2 scrollPos; + private static GUIStyle titleGuiStyle; + public static HashSet<string> keywordBlacklist = new HashSet<string>(new string[] + { + // Unity Keywords, these don't matter at all. (They should be loaded) + // All Keywords that are in Standard Unity Shaders + "_ALPHABLEND_ON", + "_ALPHAMODULATE_ON", + "_ALPHAPREMULTIPLY_ON", + "_ALPHATEST_ON", + "_COLORADDSUBDIFF_ON", + "_COLORCOLOR_ON", + "_COLOROVERLAY_ON", + "_DETAIL_MULX2", + "_EMISSION", + "_FADING_ON", + "_GLOSSYREFLECTIONS_OFF", + "_GLOSSYREFLECTIONS_OFF", + "_MAPPING_6_FRAMES_LAYOUT", + "_METALLICGLOSSMAP", + "_NORMALMAP", + "_PARALLAXMAP", + "_REQUIRE_UV2", + "_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A", + "_SPECGLOSSMAP", + "_SPECULARHIGHLIGHTS_OFF", + "_SPECULARHIGHLIGHTS_OFF", + "_SUNDISK_HIGH_QUALITY", + "_SUNDISK_NONE", + "_SUNDISK_SIMPLE", + "_TERRAIN_NORMAL_MAP", + "BILLBOARD_FACE_CAMERA_POS", + "EFFECT_BUMP", + "EFFECT_HUE_VARIATION", + "ETC1_EXTERNAL_ALPHA", + "GEOM_TYPE_BRANCH", + "GEOM_TYPE_BRANCH_DETAIL", + "GEOM_TYPE_FROND", + "GEOM_TYPE_LEAF", + "GEOM_TYPE_MESH", + "LOD_FADE_CROSSFADE", + "PIXELSNAP_ON", + "SOFTPARTICLES_ON", + "STEREO_INSTANCING_ON", + "STEREO_MULTIVIEW_ON", + "UNITY_HDR_ON", + "UNITY_SINGLE_PASS_STEREO", + "UNITY_UI_ALPHACLIP", + "UNITY_UI_CLIP_RECT", + // Post Processing Stack V1 and V2 + // This is mostly just safe keeping somewhere + "FOG_OFF", + "FOG_LINEAR", + "FOG_EXP", + "FOG_EXP2", + "ANTI_FLICKER", + "UNITY_COLORSPACE_GAMMA", + "SOURCE_GBUFFER", + "AUTO_KEY_VALUE", + "GRAIN", + "DITHERING", + "TONEMAPPING_NEUTRAL", + "TONEMAPPING_FILMIC", + "CHROMATIC_ABERRATION", + "DEPTH_OF_FIELD", + "DEPTH_OF_FIELD_COC_VIEW", + "BLOOM", + "BLOOM_LENS_DIRT", + "COLOR_GRADING", + "COLOR_GRADING_LOG_VIEW", + "USER_LUT", + "VIGNETTE_CLASSIC", + "VIGNETTE_MASKED", + "FXAA", + "FXAA_LOW", + "FXAA_KEEP_ALPHA", + "STEREO_INSTANCING_ENABLED", + "STEREO_DOUBLEWIDE_TARGET", + "TONEMAPPING_ACES", + "TONEMAPPING_CUSTOM", + "APPLY_FORWARD_FOG", + "DISTORT", + "CHROMATIC_ABERRATION_LOW", + "BLOOM_LOW", + "VIGNETTE", + "FINALPASS", + "COLOR_GRADING_HDR_3D", + "COLOR_GRADING_HDR", + "AUTO_EXPOSURE" + }); + + const string keywordDescription = "Unity has a global limit of 256 keywords. A lot (~60) are used internally by Unity.\n\nAny new keyword you encounter goes onto a global list, and will stay until you restart the client.\n\nKeywords are used to create compile time branches and remove code, to optimize a shader, however, because of the 256 keyword limit, using them in VRChat can cause other shaders which use keywords to break, as once you hit the limit, any new keyword will get ignored.\n\nIt's best in the confines of VRChat to stay away from using custom keywords if possible, as not to cause issues with (your) shaders breaking.\n\nFor the full list of internal keywords, see 'ShaderKeywordsUtility.cs'"; + + private static bool avatarsDirty = true; + private int loadedScenes = 0; + + [MenuItem("VRChat SDK/Utilities/Avatar Shader Keywords Utility", false, 990)] + static void Init() + { + ShaderKeywordsUtility window = EditorWindow.GetWindow<ShaderKeywordsUtility>(); + window.titleContent = new GUIContent("Shader Keywords Utility"); + window.minSize = new Vector2(325, 410); + window.Show(); + + titleGuiStyle = new GUIStyle + { + fontSize = 15, + fontStyle = FontStyle.BoldAndItalic, + alignment = TextAnchor.MiddleCenter, + wordWrap = true + }; + + if (EditorGUIUtility.isProSkin) + titleGuiStyle.normal.textColor = Color.white; + else + titleGuiStyle.normal.textColor = Color.black; + } + + public static List<VRC.SDKBase.VRC_AvatarDescriptor> getADescs() + { + List<GameObject> GOs = new List<GameObject>(); + for (int i = 0; i < UnityEditor.SceneManagement.EditorSceneManager.sceneCount; i++) + { + Scene scene = UnityEditor.SceneManagement.EditorSceneManager.GetSceneAt(i); + if (scene.isLoaded) + { + GameObject[] GOs2 = scene.GetRootGameObjects(); + foreach (GameObject go in GOs2) + { + GOs.Add(go); + } + } + } + + List<VRC.SDKBase.VRC_AvatarDescriptor> descriptors = new List<VRC.SDKBase.VRC_AvatarDescriptor>(); + foreach (GameObject go in GOs) + { + var vrcdescs = go.GetComponentsInChildren<VRC.SDKBase.VRC_AvatarDescriptor>(true); + foreach (VRC.SDKBase.VRC_AvatarDescriptor vrcdesc in vrcdescs) + { + descriptors.Add(vrcdesc); + } + } + + return descriptors; + } + + public static bool DetectCustomShaderKeywords(VRC.SDKBase.VRC_AvatarDescriptor ad) + { + foreach (Renderer renderer in ad.transform.GetComponentsInChildren<Renderer>(true)) + { + foreach (Material mat in renderer.sharedMaterials) + { + if (mat != null) + { + foreach (string keyword in mat.shaderKeywords) + { + if (!keywordBlacklist.Contains(keyword)) + return true; + } + } + } + } + return false; + } + + void OnGUI() + { + GUILayout.Space(10); + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.Label("Shader Keywords Utility", titleGuiStyle); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + GUILayout.Space(15); + + bool showHelp = EditorPrefs.GetBool("VRCSDK_ShowShaderKeywordsHelp", true); + if (showHelp) + { + GUILayout.Label(keywordDescription, EditorStyles.helpBox, GUILayout.ExpandWidth(true)); + GUILayout.Space(15); + } + + int _loadedScenes = 0; + for (int i = 0; i < UnityEditor.SceneManagement.EditorSceneManager.sceneCount; i++) + { + Scene scene = UnityEditor.SceneManagement.EditorSceneManager.GetSceneAt(i); + if (scene.isLoaded) + _loadedScenes += 1; + } + if (_loadedScenes != loadedScenes) + { + // Debug.Log("Loaded Scenes changed"); + loadedScenes = _loadedScenes; + avatarsDirty = true; + } + + GUILayout.BeginHorizontal(); + if (GUILayout.Button("Refresh Avatars", GUILayout.ExpandWidth(false))) + avatarsDirty = true; + GUILayout.FlexibleSpace(); + if (GUILayout.Button((showHelp ? "Hide" : "Show") + " Info about Keywords")) + { + showHelp = !showHelp; + EditorPrefs.SetBool("VRCSDK_ShowShaderKeywordsHelp", showHelp); + } + GUILayout.EndHorizontal(); + GUILayout.Space(5); + + scrollPos = EditorGUILayout.BeginScrollView(scrollPos, false, false); + ListAvatars(); + EditorGUILayout.EndScrollView(); + + } + + void ListAvatars() + { + + if (avatarsDirty) + CacheAvatars(); + + Dictionary<VRC.SDKBase.VRC_AvatarDescriptor, Dictionary<Material, bool>> avatarsE = new Dictionary<VRC.SDKBase.VRC_AvatarDescriptor, Dictionary<Material, bool>>(avatars); + foreach (VRC.SDKBase.VRC_AvatarDescriptor vrcAD in avatarsE.Keys) + { + List<string> keywords = new List<string>(); + foreach (Material mat in avatars[vrcAD].Keys) + { + foreach (string keyword in mat.shaderKeywords) + { + if (!keywords.Contains(keyword) && !keywordBlacklist.Contains(keyword)) + keywords.Add(keyword); + } + } + if (keywords.Count == 0) + { + avatars.Remove(vrcAD); + avatarsOpened.Remove(vrcAD); + continue; + } + + GUILayout.BeginHorizontal(); + bool avatarOpened = avatarsOpened[vrcAD]; + avatarOpened = EditorGUILayout.ToggleLeft("", avatarOpened, GUILayout.MaxWidth(15f)); + avatarsOpened[vrcAD] = avatarOpened; + EditorGUILayout.ObjectField(vrcAD, typeof(VRC.SDKBase.VRC_AvatarDescriptor), true); + GUILayout.EndHorizontal(); + + if (avatarOpened) + { + GUILayout.BeginHorizontal(); + GUILayout.Space(23.0879f); + GUILayout.Label("Total Custom Keywords on Avatar: " + keywords.Count); + GUILayout.EndHorizontal(); + + Dictionary<Material, bool> materials = new Dictionary<Material, bool>(avatars[vrcAD]); + foreach (KeyValuePair<Material, bool> matKeyVal in materials) + { + Material material = matKeyVal.Key; + bool materialOpened = matKeyVal.Value; + + GUILayout.BeginHorizontal(); + GUILayout.Space(23.0879f); + materialOpened = EditorGUILayout.ToggleLeft("", materialOpened, GUILayout.MaxWidth(15f)); + avatars[vrcAD][material] = materialOpened; + EditorGUILayout.ObjectField(material, typeof(Material), false); + GUILayout.EndHorizontal(); + + if (materialOpened) + { + GUILayout.BeginHorizontal(); + GUILayout.Space(23.0879f * 2f); + if (GUILayout.Button("Delete ALL Keywords on this Material")) + { + if (EditorUtility.DisplayDialog("Delete All Keywords on this Material", "Are you sure you want to delete all Shader Keywords on this material?\nSome shaders might use these!", "Yes", "No")) + { + foreach (string keyword in material.shaderKeywords) + { + if (!keywordBlacklist.Contains(keyword)) + material.DisableKeyword(keyword); + } + avatars[vrcAD].Remove(material); + } + } + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.Space(23.0879f * 2f); + GUILayout.Label("Keywords", EditorStyles.boldLabel); + GUILayout.EndHorizontal(); + + int keywordsCount = 0; + foreach (string keyword in material.shaderKeywords) + { + if (!keywordBlacklist.Contains(keyword)) + { + keywordsCount++; + GUILayout.BeginHorizontal(); + GUILayout.Space(23.0879f * 2f); + GUILayout.Label(keyword); + if (GUILayout.Button("Delete", GUILayout.ExpandWidth(false))) + material.DisableKeyword(keyword); + GUILayout.EndHorizontal(); + } + } + if (keywordsCount == 0) + avatars[vrcAD].Remove(material); + } + } + GUILayout.Space(2f); + } + } + + } + + void CacheAvatars() + { + + //Debug.Log("Caching avatars"); + avatars = new Dictionary<VRC.SDKBase.VRC_AvatarDescriptor, Dictionary<Material, bool>>(); + + List<VRC.SDKBase.VRC_AvatarDescriptor> avatarDescriptors = getADescs(); + + foreach (VRC.SDKBase.VRC_AvatarDescriptor aD in avatarDescriptors) + { + if (!avatars.ContainsKey(aD)) + avatars.Add(aD, new Dictionary<Material, bool>()); + + if (!avatarsOpened.ContainsKey(aD)) + avatarsOpened.Add(aD, false); + + foreach (Renderer renderer in aD.transform.GetComponentsInChildren<Renderer>(true)) + { + foreach (Material mat in renderer.sharedMaterials) + { + if (mat != null) + { + if (!avatars[aD].ContainsKey(mat)) + { + foreach (string keyword in mat.shaderKeywords) + { + if (!keywordBlacklist.Contains(keyword)) + { + avatars[aD].Add(mat, false); + break; + } + } + } + } + } + } + if (avatars[aD].Count == 0) + { + avatars.Remove(aD); + avatarsOpened.Remove(aD); + } + } + // prevent leaking + Dictionary<VRC.SDKBase.VRC_AvatarDescriptor, bool> avatarsOpenedE = new Dictionary<VRC.SDKBase.VRC_AvatarDescriptor, bool>(); + foreach (VRC.SDKBase.VRC_AvatarDescriptor aO in avatarsOpenedE.Keys) + { + if (!avatarDescriptors.Contains(aO)) + avatarsOpened.Remove(aO); + } + avatarsDirty = false; + + } + +} +#endif
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderKeywordsUtility.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderKeywordsUtility.cs.meta new file mode 100644 index 00000000..3c3d530f --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderKeywordsUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 679ba0056bf110c4db8b550082e73a5f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping.meta new file mode 100644 index 00000000..33173455 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a728821b457c92c46aec0b079bca3616 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/StripAndroidAvatars.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/StripAndroidAvatars.cs new file mode 100644 index 00000000..3e4a1f1a --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/StripAndroidAvatars.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; +using UnityEditor.Rendering; +using UnityEngine; +using VRC.SDKBase.Editor.BuildPipeline; + +public class StripAndroidAvatars : IPreprocessShaders, IVRCSDKBuildRequestedCallback, IPostprocessBuildWithReport +{ + private static VRCSDKRequestedBuildType? _buildType = null; + + public int callbackOrder => 0; + + public bool OnBuildRequested(VRCSDKRequestedBuildType requestedBuildType) + { + _buildType = requestedBuildType; + return true; + } + + public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> data) + { + if(_buildType != VRCSDKRequestedBuildType.Avatar) + { + return; + } + + if(EditorUserBuildSettings.activeBuildTarget != BuildTarget.Android) + { + return; + } + + data.Clear(); + } + + public void OnPostprocessBuild(BuildReport report) + { + _buildType = null; + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/StripAndroidAvatars.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/StripAndroidAvatars.cs.meta new file mode 100644 index 00000000..cad09752 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/StripAndroidAvatars.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3f05fc74d61cc0c448411f8b55c918ca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/StripPostProcessing.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/StripPostProcessing.cs new file mode 100644 index 00000000..0b0cac3a --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/StripPostProcessing.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Rendering; +using UnityEngine; + +namespace VRC.SDKBase.Editor.ShaderStripping +{ + public class StripPostProcessing : IPreprocessShaders + { + public int callbackOrder => 0; + + public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> data) + { + if(EditorUserBuildSettings.activeBuildTarget != BuildTarget.Android) + { + return; + } + + string shaderName = shader.name; + if(string.IsNullOrEmpty(shaderName) || !shaderName.Contains("PostProcessing")) + { + return; + } + + data.Clear(); + } + } +}
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/StripPostProcessing.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/StripPostProcessing.cs.meta new file mode 100644 index 00000000..f40ffb5c --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/StripPostProcessing.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 06d01ef00e2795244aa8b5cbe879b16e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/VRC.SDKBase.Editor.ShaderStripping.asmdef b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/VRC.SDKBase.Editor.ShaderStripping.asmdef new file mode 100644 index 00000000..6a0bf26a --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/VRC.SDKBase.Editor.ShaderStripping.asmdef @@ -0,0 +1,16 @@ +{ + "name": "VRC.SDKBase.Editor.ShaderStripping", + "references": [], + "optionalUnityReferences": [], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [ + "VRCSDKBase-Editor.dll" + ], + "autoReferenced": true, + "defineConstraints": [] +}
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/VRC.SDKBase.Editor.ShaderStripping.asmdef.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/VRC.SDKBase.Editor.ShaderStripping.asmdef.meta new file mode 100644 index 00000000..b49d7def --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/ShaderStripping/VRC.SDKBase.Editor.ShaderStripping.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 09158b5a87ea9554daafaef906ae927e +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRCCachedWebRequest.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRCCachedWebRequest.cs new file mode 100644 index 00000000..2dab5f97 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRCCachedWebRequest.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using UnityEngine; +using UnityEngine.Networking; + +public static class VRCCachedWebRequest +{ + private const float DefaultCacheTimeHours = 24 * 7; + + public static void ClearOld(float cacheLimitHours = DefaultCacheTimeHours) + { + string cacheDir = CacheDir; + if(!Directory.Exists(cacheDir)) + { + return; + } + + foreach(string fileName in Directory.GetFiles(cacheDir)) + { + if(!(GetAge(fileName) > cacheLimitHours)) + { + continue; + } + + Debug.Log($"Deleting {fileName}"); + File.Delete(fileName); + } + } + + private static string CacheDir => Application.temporaryCachePath; + + public static IEnumerator Get(string url, Action<Texture2D> onDone, float cacheLimitHours = DefaultCacheTimeHours) + { + string cacheDir = CacheDir; + if(!Directory.Exists(cacheDir)) + { + Directory.CreateDirectory(cacheDir); + } + + string hash = CreateHash(url); + string cache = cacheDir + "/www_" + hash; + + if(File.Exists(cache)) + { + // Use cached file if it exists + if(GetAge(cache) > cacheLimitHours) + { + File.Delete(cache); + } + else + { + Texture2D texture = new Texture2D(2, 2); + if(!texture.LoadImage(File.ReadAllBytes(cache))) + { + yield break; + } + + // load texture from disk and exit if we successfully read it + texture.Apply(); + onDone(texture); + } + } + + else + { + // No cached file, load it from url + using(UnityWebRequest uwr = UnityWebRequestTexture.GetTexture(url)) + { + // Wait until request and download are complete + yield return uwr.SendWebRequest(); + while(!uwr.isDone || !uwr.downloadHandler.isDone) + { + yield return null; + } + + var texture = DownloadHandlerTexture.GetContent(uwr); + + if(string.IsNullOrEmpty(uwr.error)) + { + File.WriteAllBytes(cache, uwr.downloadHandler.data); + } + + onDone(texture); + } + } + } + + private static string CreateHash(string input) + { + SHA256 hash = SHA256.Create(); + byte[] computedHash = hash.ComputeHash(Encoding.Default.GetBytes(input)); + return Uri.EscapeDataString(Convert.ToBase64String(computedHash)); + } + + private static double GetAge(string file) + { + if(!File.Exists(file)) + { + return 0; + } + + DateTime writeTime = File.GetLastWriteTimeUtc(file); + return DateTime.UtcNow.Subtract(writeTime).TotalHours; + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRCCachedWebRequest.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRCCachedWebRequest.cs.meta new file mode 100644 index 00000000..529acc63 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRCCachedWebRequest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0d2c09d149d213846ac4bdab38be0385 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRC_EditorTools.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRC_EditorTools.cs new file mode 100644 index 00000000..50e69d6a --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRC_EditorTools.cs @@ -0,0 +1,457 @@ +#if UNITY_EDITOR +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; +using System.Linq; +using UnityEditorInternal; +using System.Reflection; +using System; + +namespace VRC.SDKBase +{ + public static class VRC_EditorTools + { + private static LayerMask LayerMaskPopupInternal(LayerMask selectedValue, System.Func<int, string[], int> showMask) + { + string[] layerNames = InternalEditorUtility.layers; + List<int> layerNumbers = new List<int>(); + + foreach (string layer in layerNames) + layerNumbers.Add(LayerMask.NameToLayer(layer)); + + int mask = 0; + for (int idx = 0; idx < layerNumbers.Count; ++idx) + if (((1 << layerNumbers[idx]) & selectedValue.value) > 0) + mask |= (1 << idx); + + mask = showMask(mask, layerNames); + + selectedValue.value = 0; + for (int idx = 0; idx < layerNumbers.Count; ++idx) + if (((1 << idx) & mask) > 0) + selectedValue.value |= (1 << layerNumbers[idx]); + + return selectedValue; + } + + public static LayerMask LayerMaskPopup(LayerMask selectedValue, params GUILayoutOption[] options) + { + return LayerMaskPopupInternal(selectedValue, (mask, layerNames) => EditorGUILayout.MaskField(mask, layerNames, options)); + } + + public static LayerMask LayerMaskPopup(string label, LayerMask selectedValue, params GUILayoutOption[] options) + { + return LayerMaskPopupInternal(selectedValue, (mask, layerNames) => EditorGUILayout.MaskField(label, mask, layerNames, options)); + } + + public static LayerMask LayerMaskPopup(Rect rect, LayerMask selectedValue, GUIStyle style = null) + { + System.Func<int, string[], int> show = (mask, layerNames) => + { + if (style == null) + return EditorGUI.MaskField(rect, mask, layerNames); + else + return EditorGUI.MaskField(rect, mask, layerNames, style); + }; + return LayerMaskPopupInternal(selectedValue, show); + } + + public static LayerMask LayerMaskPopup(Rect rect, string label, LayerMask selectedValue, GUIStyle style = null) + { + System.Func<int, string[], int> show = (mask, layerNames) => + { + if (style == null) + return EditorGUI.MaskField(rect, label, mask, layerNames); + else + return EditorGUI.MaskField(rect, label, mask, layerNames, style); + }; + return LayerMaskPopupInternal(selectedValue, show); + } + + private static T FilteredEnumPopupInternal<T>(T selectedValue, System.Func<T, bool> predicate, System.Func<int, string[], int> showPopup, System.Func<string, string> rename) where T : struct, System.IConvertible + { + if (!typeof(T).IsEnum) + throw new System.ArgumentException(typeof(T).Name + " is not an Enum", "T"); + + T[] ary = System.Enum.GetValues(typeof(T)).Cast<T>().Where(v => predicate(v)).ToArray(); + string[] names = ary.Select(e => System.Enum.GetName(typeof(T), e)).ToArray(); + + int selectedIdx = 0; + for (; selectedIdx < ary.Length; ++selectedIdx) + if (ary[selectedIdx].Equals(selectedValue)) + break; + if (selectedIdx == ary.Length) + selectedIdx = 0; + + if (ary.Length == 0) + throw new System.ArgumentException("Predicate filtered out all options", "predicate"); + + if (rename != null) + return ary[showPopup(selectedIdx, names.Select(rename).ToArray())]; + else + return ary[showPopup(selectedIdx, names)]; + } + + private static void FilteredEnumPopupInternal<T>(SerializedProperty enumProperty, System.Func<T, bool> predicate, System.Func<int, string[], int> showPopup, System.Func<string, string> rename) where T : struct, System.IConvertible + { + string selectedName = enumProperty.enumNames[enumProperty.enumValueIndex]; + T selectedValue = FilteredEnumPopupInternal<T>((T)System.Enum.Parse(typeof(T), selectedName), predicate, showPopup, rename); + selectedName = selectedValue.ToString(); + for (int idx = 0; idx < enumProperty.enumNames.Length; ++idx) + if (enumProperty.enumNames[idx] == selectedName) + { + enumProperty.enumValueIndex = idx; + break; + } + } + + public static T FilteredEnumPopup<T>(string label, T selectedValue, System.Func<T, bool> predicate, System.Func<string, string> rename = null, params GUILayoutOption[] options) where T : struct, System.IConvertible + { + return FilteredEnumPopupInternal(selectedValue, predicate, (selectedIdx, names) => EditorGUILayout.Popup(label, selectedIdx, names, options), rename); + } + + public static T FilteredEnumPopup<T>(T selectedValue, System.Func<T, bool> predicate, System.Func<string, string> rename = null, params GUILayoutOption[] options) where T : struct, System.IConvertible + { + return FilteredEnumPopupInternal(selectedValue, predicate, (selectedIdx, names) => EditorGUILayout.Popup(selectedIdx, names, options), rename); + } + + public static T FilteredEnumPopup<T>(Rect rect, string label, T selectedValue, System.Func<T, bool> predicate, System.Func<string, string> rename = null, GUIStyle style = null) where T : struct, System.IConvertible + { + System.Func<int, string[], int> show = (selectedIdx, names) => + { + if (style != null) + return EditorGUI.Popup(rect, label, selectedIdx, names, style); + else + return EditorGUI.Popup(rect, label, selectedIdx, names); + }; + return FilteredEnumPopupInternal(selectedValue, predicate, show, rename); + } + + public static T FilteredEnumPopup<T>(Rect rect, T selectedValue, System.Func<T, bool> predicate, System.Func<string, string> rename = null, GUIStyle style = null) where T : struct, System.IConvertible + { + System.Func<int, string[], int> show = (selectedIdx, names) => + { + if (style != null) + return EditorGUI.Popup(rect, selectedIdx, names, style); + else + return EditorGUI.Popup(rect, selectedIdx, names); + }; + return FilteredEnumPopupInternal(selectedValue, predicate, show, rename); + } + + public static void FilteredEnumPopup<T>(string label, SerializedProperty selectedValue, System.Func<T, bool> predicate, System.Func<string, string> rename = null, params GUILayoutOption[] options) where T : struct, System.IConvertible + { + FilteredEnumPopupInternal(selectedValue, predicate, (selectedIdx, names) => EditorGUILayout.Popup(label, selectedIdx, names, options), rename); + } + + public static void FilteredEnumPopup<T>(SerializedProperty selectedValue, System.Func<T, bool> predicate, System.Func<string, string> rename = null, params GUILayoutOption[] options) where T : struct, System.IConvertible + { + FilteredEnumPopupInternal(selectedValue, predicate, (selectedIdx, names) => EditorGUILayout.Popup(selectedIdx, names, options), rename); + } + + public static void FilteredEnumPopup<T>(Rect rect, string label, SerializedProperty selectedValue, System.Func<T, bool> predicate, System.Func<string, string> rename = null, GUIStyle style = null) where T : struct, System.IConvertible + { + System.Func<int, string[], int> show = (selectedIdx, names) => + { + if (style != null) + return EditorGUI.Popup(rect, label, selectedIdx, names, style); + else + return EditorGUI.Popup(rect, label, selectedIdx, names); + }; + FilteredEnumPopupInternal(selectedValue, predicate, show, rename); + } + + public static void FilteredEnumPopup<T>(Rect rect, SerializedProperty selectedValue, System.Func<T, bool> predicate, System.Func<string, string> rename = null, GUIStyle style = null) where T : struct, System.IConvertible + { + System.Func<int, string[], int> show = (selectedIdx, names) => + { + if (style != null) + return EditorGUI.Popup(rect, selectedIdx, names, style); + else + return EditorGUI.Popup(rect, selectedIdx, names); + }; + FilteredEnumPopupInternal(selectedValue, predicate, show, rename); + } + + private static VRC.SDKBase.VRC_Trigger.TriggerEvent CustomTriggerPopupInternal(VRC.SDKBase.VRC_Trigger sourceTrigger, VRC.SDKBase.VRC_Trigger.TriggerEvent selectedValue, System.Func<int, string[], int> show) + { + if (sourceTrigger == null) + return null; + + VRC.SDKBase.VRC_Trigger.TriggerEvent[] actionsAry = sourceTrigger.Triggers.Where(t => t.TriggerType == VRC.SDKBase.VRC_Trigger.TriggerType.Custom).ToArray(); + string[] names = actionsAry.Select(t => t.Name).ToArray(); + + int selectedIdx = Math.Max(0, names.Length - 1); + if (selectedValue != null) + for (; selectedIdx > 0; --selectedIdx) + if (names[selectedIdx] == selectedValue.Name) + break; + if (actionsAry.Length == 0) + return null; + + return actionsAry[show(selectedIdx, names)]; + } + + public static VRC.SDKBase.VRC_Trigger.TriggerEvent CustomTriggerPopup(Rect rect, VRC.SDKBase.VRC_Trigger sourceTrigger, VRC.SDKBase.VRC_Trigger.TriggerEvent selectedValue, GUIStyle style = null) + { + System.Func<int, string[], int> show = (selectedIdx, names) => + { + if (style != null) + return EditorGUI.Popup(rect, selectedIdx, names, style); + else + return EditorGUI.Popup(rect, selectedIdx, names); + }; + + return CustomTriggerPopupInternal(sourceTrigger, selectedValue, show); + } + + public static VRC.SDKBase.VRC_Trigger.TriggerEvent CustomTriggerPopup(Rect rect, string label, VRC.SDKBase.VRC_Trigger sourceTrigger, VRC.SDKBase.VRC_Trigger.TriggerEvent selectedValue, GUIStyle style = null) + { + System.Func<int, string[], int> show = (selectedIdx, names) => + { + if (style != null) + return EditorGUI.Popup(rect, label, selectedIdx, names, style); + else + return EditorGUI.Popup(rect, label, selectedIdx, names); + }; + + return CustomTriggerPopupInternal(sourceTrigger, selectedValue, show); + } + + public static VRC.SDKBase.VRC_Trigger.TriggerEvent CustomTriggerPopup(VRC.SDKBase.VRC_Trigger sourceTrigger, VRC.SDKBase.VRC_Trigger.TriggerEvent selectedValue, params GUILayoutOption[] options) + { + return CustomTriggerPopupInternal(sourceTrigger, selectedValue, (selectedIdx, names) => EditorGUILayout.Popup(selectedIdx, names, options)); + } + + public static VRC.SDKBase.VRC_Trigger.TriggerEvent CustomTriggerPopup(string label, VRC.SDKBase.VRC_Trigger sourceTrigger, VRC.SDKBase.VRC_Trigger.TriggerEvent selectedValue, params GUILayoutOption[] options) + { + return CustomTriggerPopupInternal(sourceTrigger, selectedValue, (selectedIdx, names) => EditorGUILayout.Popup(label, selectedIdx, names, options)); + } + + public static VRC.SDKBase.VRC_Trigger.TriggerEvent CustomTriggerPopup(string label, VRC.SDKBase.VRC_Trigger sourceTrigger, string selectedValue, params GUILayoutOption[] options) + { + if (sourceTrigger == null) + return null; + + return CustomTriggerPopup(label, sourceTrigger, sourceTrigger.Triggers.FirstOrDefault(t => t.TriggerType == VRC.SDKBase.VRC_Trigger.TriggerType.Custom && t.Name == selectedValue), options); + } + + public static VRC.SDKBase.VRC_Trigger.TriggerEvent CustomTriggerPopup(VRC.SDKBase.VRC_Trigger sourceTrigger, string selectedValue, params GUILayoutOption[] options) + { + if (sourceTrigger == null) + return null; + + return CustomTriggerPopup(sourceTrigger, sourceTrigger.Triggers.FirstOrDefault(t => t.TriggerType == VRC.SDKBase.VRC_Trigger.TriggerType.Custom && t.Name == selectedValue), options); + } + + public static VRC.SDKBase.VRC_Trigger.TriggerEvent CustomTriggerPopup(Rect rect, VRC.SDKBase.VRC_Trigger sourceTrigger, string selectedValue, GUIStyle style = null) + { + if (sourceTrigger == null) + return null; + + return CustomTriggerPopup(rect, sourceTrigger, sourceTrigger.Triggers.FirstOrDefault(t => t.TriggerType == VRC.SDKBase.VRC_Trigger.TriggerType.Custom && t.Name == selectedValue), style); + } + + public static VRC.SDKBase.VRC_Trigger.TriggerEvent CustomTriggerPopup(Rect rect, string label, VRC.SDKBase.VRC_Trigger sourceTrigger, string selectedValue, GUIStyle style = null) + { + if (sourceTrigger == null) + return null; + + return CustomTriggerPopup(rect, label, sourceTrigger, sourceTrigger.Triggers.FirstOrDefault(t => t.TriggerType == VRC.SDKBase.VRC_Trigger.TriggerType.Custom && t.Name == selectedValue), style); + } + + private static void InternalSerializedCustomTriggerPopup(SerializedProperty triggersProperty, SerializedProperty customProperty, System.Func<int, string[], int> show, System.Action fail) + { + if (customProperty == null || (customProperty.propertyType != SerializedPropertyType.String)) + throw new ArgumentException("Expected a string for customProperty"); + if (triggersProperty == null || (!triggersProperty.isArray && triggersProperty.propertyType != SerializedPropertyType.ObjectReference)) + throw new ArgumentException("Expected an object or array for triggersProperty"); + + List<String> customNames = new List<string>(); + bool allNull = true; + + if (triggersProperty.isArray) + { + int idx; + for (idx = 0; idx < triggersProperty.arraySize; ++idx) + { + GameObject obj = triggersProperty.GetArrayElementAtIndex(idx).objectReferenceValue as GameObject; + if (obj != null) + { + customNames = obj.GetComponent<VRC.SDKBase.VRC_Trigger>().Triggers.Where(t => t.TriggerType == VRC.SDKBase.VRC_Trigger.TriggerType.Custom).Select(t => t.Name).ToList(); + allNull = false; + break; + } + } + for (; idx < triggersProperty.arraySize; ++idx) + { + GameObject obj = triggersProperty.GetArrayElementAtIndex(idx).objectReferenceValue as GameObject; + if (obj != null) + { + List<string> thisCustomNames = obj.GetComponent<VRC.SDKBase.VRC_Trigger>().Triggers.Where(t => t.TriggerType == VRC.SDKBase.VRC_Trigger.TriggerType.Custom).Select(t => t.Name).ToList(); + customNames.RemoveAll(s => thisCustomNames.Contains(s) == false); + } + } + } + else + { + GameObject obj = triggersProperty.objectReferenceValue as GameObject; + if (obj != null) + { + allNull = false; + customNames = obj.GetComponent<VRC.SDKBase.VRC_Trigger>().Triggers.Where(t => t.TriggerType == VRC.SDKBase.VRC_Trigger.TriggerType.Custom).Select(t => t.Name).ToList(); + } + } + + if (customNames.Count == 0 && !allNull && triggersProperty.isArray) + { + fail(); + customProperty.stringValue = ""; + } + else + { + if (customNames.Count == 0) + customNames.Add(""); + + int selectedIdx = Math.Max(0, customNames.Count - 1); + if (!string.IsNullOrEmpty(customProperty.stringValue)) + for (; selectedIdx > 0; --selectedIdx) + if (customNames[selectedIdx] == customProperty.stringValue) + break; + + selectedIdx = show(selectedIdx, customNames.ToArray()); + customProperty.stringValue = customNames[selectedIdx]; + } + } + + public static void CustomTriggerPopup(string label, SerializedProperty triggersProperty, SerializedProperty customProperty, params GUILayoutOption[] options) + { + InternalSerializedCustomTriggerPopup(triggersProperty, customProperty, (idx, names) => EditorGUILayout.Popup(label, idx, names, options), () => EditorGUILayout.HelpBox("Receivers do not have Custom Triggers which share names.", MessageType.Warning)); + } + + public static void CustomTriggerPopup(SerializedProperty triggersProperty, SerializedProperty customProperty, params GUILayoutOption[] options) + { + InternalSerializedCustomTriggerPopup(triggersProperty, customProperty, (idx, names) => EditorGUILayout.Popup(idx, names, options), () => EditorGUILayout.HelpBox("Receivers do not have Custom Triggers which share names.", MessageType.Warning)); + } + + public static void CustomTriggerPopup(Rect rect, SerializedProperty triggersProperty, SerializedProperty customProperty, GUIStyle style = null) + { + InternalSerializedCustomTriggerPopup(triggersProperty, customProperty, (idx, names) => style == null ? EditorGUI.Popup(rect, idx, names) : EditorGUI.Popup(rect, idx, names, style), () => EditorGUI.HelpBox(rect, "Receivers do not have Custom Triggers which share names.", MessageType.Warning)); + } + + public static void CustomTriggerPopup(Rect rect, string label, SerializedProperty triggersProperty, SerializedProperty customProperty, GUIStyle style = null) + { + InternalSerializedCustomTriggerPopup(triggersProperty, customProperty, (idx, names) => style == null ? EditorGUI.Popup(rect, label, idx, names) : EditorGUI.Popup(rect, label, idx, names, style), () => EditorGUI.HelpBox(rect, "Receivers do not have Custom Triggers which share names.", MessageType.Warning)); + } + + public static void DrawTriggerActionCallback(string actionLabel, VRC.SDKBase.VRC_Trigger trigger, VRC.SDKBase.VRC_EventHandler.VrcEvent e) + { + VRC.SDKBase.VRC_Trigger.TriggerEvent triggerEvent = VRC_EditorTools.CustomTriggerPopup(actionLabel, trigger, e.ParameterString); + e.ParameterString = triggerEvent == null ? null : triggerEvent.Name; + } + + public static Dictionary<string, List<MethodInfo>> GetSharedAccessibleMethodsOnGameObjects(SerializedProperty objectsProperty) + { + Dictionary<string, List<MethodInfo>> methods = new Dictionary<string, List<MethodInfo>>(); + + int idx = 0; + for (; idx < objectsProperty.arraySize; ++idx) + { + SerializedProperty prop = objectsProperty.GetArrayElementAtIndex(idx); + GameObject obj = prop.objectReferenceValue != null ? prop.objectReferenceValue as GameObject : null; + if (obj != null) + { + methods = VRC_EditorTools.GetAccessibleMethodsOnGameObject(obj); + break; + } + } + List<string> toRemove = new List<string>(); + for (; idx < objectsProperty.arraySize; ++idx) + { + SerializedProperty prop = objectsProperty.GetArrayElementAtIndex(idx); + GameObject obj = prop.objectReferenceValue != null ? prop.objectReferenceValue as GameObject : null; + if (obj != null) + { + Dictionary<string, List<MethodInfo>> thisObjMethods = VRC_EditorTools.GetAccessibleMethodsOnGameObject(obj); + foreach (string className in methods.Keys.Where(s => thisObjMethods.Keys.Contains(s) == false)) + toRemove.Add(className); + } + } + + foreach (string className in toRemove) + methods.Remove(className); + + return methods; + } + + public static Dictionary<string, List<MethodInfo>> GetAccessibleMethodsOnGameObject(GameObject go) + { + Dictionary<string, List<MethodInfo>> methods = new Dictionary<string, List<MethodInfo>>(); + if (go == null) + return methods; + + Component[] cs = go.GetComponents<Component>(); + if (cs == null) + return methods; + + foreach (Component c in cs.Where(co => co != null)) + { + Type t = c.GetType(); + + if (methods.ContainsKey(t.Name)) + continue; + + // if component is the eventhandler + if (t == typeof(VRC.SDKBase.VRC_EventHandler)) + continue; + + List<MethodInfo> l = GetAccessibleMethodsForClass(t); + methods.Add(t.Name, l); + } + + return methods; + } + + public static List<MethodInfo> GetAccessibleMethodsForClass(Type t) + { + // Get the public methods. + MethodInfo[] myArrayMethodInfo = t.GetMethods(BindingFlags.Public | BindingFlags.Instance); + List<MethodInfo> methods = new List<MethodInfo>(); + + // if component is in UnityEngine namespace, skip it + if (!string.IsNullOrEmpty(t.Namespace) && (t.Namespace.Contains("UnityEngine") || t.Namespace.Contains("UnityEditor"))) + return methods; + + bool isVRCSDK2 = !string.IsNullOrEmpty(t.Namespace) && t.Namespace.Contains("VRCSDK2"); + + // Display information for all methods. + for (int i = 0; i < myArrayMethodInfo.Length; i++) + { + MethodInfo myMethodInfo = (MethodInfo)myArrayMethodInfo[i]; + + // if it's VRCSDK2, require RPC + if (isVRCSDK2 && myMethodInfo.GetCustomAttributes(typeof(VRC.SDKBase.RPC), true).Length == 0) + continue; + + methods.Add(myMethodInfo); + } + return methods; + } + + public static byte[] ReadBytesFromProperty(SerializedProperty property) + { + byte[] bytes = new byte[property.arraySize]; + for (int idx = 0; idx < property.arraySize; ++idx) + bytes[idx] = (byte)property.GetArrayElementAtIndex(idx).intValue; + return bytes; + } + + public static void WriteBytesToProperty(SerializedProperty property, byte[] bytes) + { + property.arraySize = bytes != null ? bytes.Length : 0; + for (int idx = 0; idx < property.arraySize; ++idx) + property.GetArrayElementAtIndex(idx).intValue = (int)bytes[idx]; + } + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRC_EditorTools.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRC_EditorTools.cs.meta new file mode 100644 index 00000000..95b84813 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRC_EditorTools.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: cb5d1f9882b08564cae97b2b14ad4e8f +timeCreated: 1474562948 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRC_SdkSplashScreen.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRC_SdkSplashScreen.cs new file mode 100644 index 00000000..8f80c939 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRC_SdkSplashScreen.cs @@ -0,0 +1,265 @@ +#define COMMUNITY_LABS_SDK + +using UnityEngine; +using UnityEditor; + +namespace VRCSDK2 +{ + [InitializeOnLoad] + public class VRC_SdkSplashScreen : EditorWindow + { + + static VRC_SdkSplashScreen() + { + EditorApplication.update -= DoSplashScreen; + EditorApplication.update += DoSplashScreen; + } + + private static void DoSplashScreen() + { + EditorApplication.update -= DoSplashScreen; + if (EditorApplication.isPlaying) + return; + + #if UDON + if (!EditorPrefs.GetBool("VRCSDK_ShowedSplashScreenFirstTime", false)) + { + OpenSplashScreen(); + EditorPrefs.SetBool("VRCSDK_ShowedSplashScreenFirstTime", true); + } + else + #endif + if (EditorPrefs.GetBool("VRCSDK_ShowSplashScreen", true)) + OpenSplashScreen(); + } + + private static GUIStyle vrcSdkHeader; + private static GUIStyle vrcSdkBottomHeader; + private static GUIStyle vrcHeaderLearnMoreButton; + private static GUIStyle vrcBottomHeaderLearnMoreButton; + private static Vector2 changeLogScroll; + [MenuItem("VRChat SDK/Splash Screen", false, 500)] + public static void OpenSplashScreen() + { + GetWindow<VRC_SdkSplashScreen>(true); + } + + public static void Open() + { + OpenSplashScreen(); + } + + public void OnEnable() + { + titleContent = new GUIContent("VRChat SDK"); + +#if UDON + maxSize = new Vector2(400, 360); +#else + maxSize = new Vector2(400, 600); +#endif + minSize = maxSize; + + vrcSdkHeader = new GUIStyle + { + normal = + { +#if UDON + background = Resources.Load("vrcSdkSplashUdon1") as Texture2D, +#elif COMMUNITY_LABS_SDK + background = Resources.Load("vrcSdkHeaderWithCommunityLabs") as Texture2D, +#else + background = Resources.Load("vrcSdkHeader") as Texture2D, +#endif + textColor = Color.white + }, + fixedHeight = 200 + }; + + vrcSdkBottomHeader = new GUIStyle + { + normal = + { +#if UDON + background = Resources.Load("vrcSdkSplashUdon2") as Texture2D, +#else + background = Resources.Load("vrcSdkBottomHeader") as Texture2D, +#endif + + textColor = Color.white + }, + fixedHeight = 100 + }; + + } + + public void OnGUI() + { + GUILayout.Box("", vrcSdkHeader); + + vrcHeaderLearnMoreButton = EditorStyles.miniButton; + vrcHeaderLearnMoreButton.normal.textColor = Color.black; + vrcHeaderLearnMoreButton.fontSize = 12; + vrcHeaderLearnMoreButton.border = new RectOffset(10, 10, 10, 10); + Texture2D texture = UnityEditor.AssetDatabase.GetBuiltinExtraResource<Texture2D>("UI/Skin/UISprite.psd"); + vrcHeaderLearnMoreButton.normal.background = texture; + vrcHeaderLearnMoreButton.active.background = texture; +#if UDON + if (GUI.Button(new Rect(20, 165, 185, 25), "Get Started with Udon", vrcHeaderLearnMoreButton)) + Application.OpenURL("https://docs.vrchat.com/docs/getting-started-with-udon"); +#elif COMMUNITY_LABS_SDK + if (GUI.Button(new Rect(20, 140, 180, 40), "Please Read", vrcHeaderLearnMoreButton)) + Application.OpenURL(CommunityLabsConstants.COMMUNITY_LABS_DOCUMENTATION_URL); +#endif + +#if !UDON + GUILayout.Space(4); + GUILayout.BeginHorizontal(); + GUI.backgroundColor = Color.gray; + if (GUILayout.Button("SDK Docs")) + { + Application.OpenURL("https://docs.vrchat.com/"); + } + if (GUILayout.Button("VRChat FAQ")) + { + Application.OpenURL("https://vrchat.com/developer-faq"); + } + if (GUILayout.Button("Help Center")) + { + Application.OpenURL("http://help.vrchat.com"); + } + if(GUILayout.Button("Examples")) + { + Application.OpenURL("https://docs.vrchat.com/docs/vrchat-kits"); + } + GUI.backgroundColor = Color.white; + GUILayout.EndHorizontal(); +#endif + GUILayout.Space(4); + GUILayout.BeginHorizontal(); + + GUI.backgroundColor = Color.gray; +#if UDON + + if(GUILayout.Button("Udon Examples")) + { + Application.OpenURL("https://docs.vrchat.com/docs/examples#udon--sdk3"); + }; +#endif + if (GUILayout.Button("Building VRChat Quest Content")) + { + Application.OpenURL("https://docs.vrchat.com/docs/creating-content-for-the-oculus-quest"); + } + GUI.backgroundColor = Color.white; + GUILayout.EndHorizontal(); + GUILayout.Space(2); +#if !UDON + changeLogScroll = GUILayout.BeginScrollView(changeLogScroll, false, false, GUIStyle.none, GUI.skin.verticalScrollbar, GUILayout.Width(395)); + + GUILayout.Label( + @"Changelog: +2019.2.4-SDK1 +- Removed upload-preventing polygon limits for avatars in SDK. +- This does not change behavior in the client. Although +you can upload content that goes beyond client limits +(for example, the Quest polygon limit), it will not render +in VRChat according to the Minimum Performance Rank setting + +2019.2.4 +- Implemented Quest Avatar limits. If your avatar is +ranked as Very Poor, you will not be able to upload +the avatar. +- If you do upload an avatar beyond the Very Poor +limits, it will not render in VRChat Quest regardless + +2019.2.3 +- Added a VRChat/Mobile/Standard Lite for use on +Oculus Quest avatars +- Standard Lite offers slots for Diffuse, Normal maps, +Metallic+Smoothness maps, and optional Emission maps +- Standard Lite uses a simplified version of BRDF for +lighting + +2019.2.2 +- Added links to the splash screen leading users to our +Quest documentation +- Added Quest shaders to SDK, available under the VRChat +category +- Quest will only support these shaders on avatars. If +you use any other shader, you'll get a warning in the +SDK. If you try to use the shader anyways, it will +fail to load in the client. You can read more about +these shaders in our documentation +- Added warnings when attempting to use unsupported +shaders on Quest +- Added errors when you attempt to upload content +too large for Quest (50mb for worlds, 10mb for +avatars). Build size is determined after package is +created. This will also be enforced in-client for Quest + +2019.1.4p2 +- Fixed an issue causing redundant error messaging when +informing the user that there are objects that share the +same path + +2019.1.4 +- Some additional tooltips in VRC_Mirror inspector for +clarity +- Added a field for a custom shader on mirrors, allowing +the mirror shader to be overridden without the need to +swap materials +using an animator +- Added a drop-down option for mirrors allowing for the +setting of lower fixed resolutions + +2019.1.3 +- Implemented features to enable usage of Community Labs + - Added Community Labs checkbox in the Publish World +screen +- Publishing a world no longer changes its release status. +If you update a Public World, it now remains public +- Changed and updated SDK UI in some places +- Mirrors should now display properly in the editor as +we've moved the necessary shader into place + +2019.1.1 +- Content Manager now behaves better when resizing +the window and scales the contents appropriately" + ); + GUILayout.EndScrollView(); +#endif + GUILayout.Space(4); + + GUILayout.Box("", vrcSdkBottomHeader); + vrcBottomHeaderLearnMoreButton = EditorStyles.miniButton; + vrcBottomHeaderLearnMoreButton.normal.textColor = Color.black; + vrcBottomHeaderLearnMoreButton.fontSize = 10; + vrcBottomHeaderLearnMoreButton.border = new RectOffset(10, 10, 10, 10); + vrcBottomHeaderLearnMoreButton.normal.background = texture; + vrcBottomHeaderLearnMoreButton.active.background = texture; + +#if UDON + if (GUI.Button(new Rect(100, 270, 200, 60), "Join other Creators in our Discord", vrcBottomHeaderLearnMoreButton)) + Application.OpenURL("https://discord.gg/vrchat"); +#else + if (GUI.Button(new Rect(110, 525, 180, 42), "Click Here to see great\nassets for VRChat creation", vrcBottomHeaderLearnMoreButton)) + Application.OpenURL("https://assetstore.unity.com/lists/vrchat-picks-125734?aid=1101l7yuQ"); +#endif + + //if (GUI.Button(new Rect(80, 540, 240, 30), "Learn how to create for VRChat Quest!", vrcBottomHeaderLearnMoreButton)) + //{ + // Application.OpenURL("https://docs.vrchat.com/docs/creating-content-for-the-oculus-quest"); + //} + + GUILayout.FlexibleSpace(); + + GUILayout.BeginHorizontal(); + + GUILayout.FlexibleSpace(); + EditorPrefs.SetBool("VRCSDK_ShowSplashScreen", GUILayout.Toggle(EditorPrefs.GetBool("VRCSDK_ShowSplashScreen"), "Show at Startup")); + + GUILayout.EndHorizontal(); + } + + } +}
\ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRC_SdkSplashScreen.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRC_SdkSplashScreen.cs.meta new file mode 100644 index 00000000..3a808579 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/VRC_SdkSplashScreen.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f4cf5dd705ab67149afaba40b4a8fa7e +timeCreated: 1527894587 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Validation.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Validation.meta new file mode 100644 index 00000000..92c4ff98 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Validation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2e09f03d39206ce4f88113f4b2d5d1cc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Validation/Performance.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Validation/Performance.meta new file mode 100644 index 00000000..16db2ac8 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Validation/Performance.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d7dcbecd095270b4db53ebf08f236c85 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Validation/Performance/SDKPerformanceDisplay.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Validation/Performance/SDKPerformanceDisplay.cs new file mode 100644 index 00000000..da66c921 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Validation/Performance/SDKPerformanceDisplay.cs @@ -0,0 +1,965 @@ +using VRC.SDKBase.Validation.Performance.Stats; + +namespace VRC.SDKBase.Validation.Performance +{ + public static class SDKPerformanceDisplay + { + public static void GetSDKPerformanceInfoText( + AvatarPerformanceStats perfStats, + AvatarPerformanceCategory perfCategory, + out string text, + out PerformanceInfoDisplayLevel displayLevel + ) + { + text = ""; + displayLevel = PerformanceInfoDisplayLevel.None; + + PerformanceRating rating = perfStats.GetPerformanceRatingForCategory(perfCategory); + switch(perfCategory) + { + case AvatarPerformanceCategory.Overall: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Info; + text = string.Format("Overall Performance: {0}", AvatarPerformanceStats.GetPerformanceRatingDisplayName(rating)); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Overall Performance: {0} - This avatar may not perform well on many systems." + + " See additional warnings for suggestions on how to improve performance. Click 'Avatar Optimization Tips' below for more information.", + AvatarPerformanceStats.GetPerformanceRatingDisplayName(rating) + ); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + if(VRC.ValidationHelpers.IsMobilePlatform()) + { + text = string.Format( + "Overall Performance: {0} - This avatar does not meet minimum performance requirements for VRChat. " + + "It will be blocked by default on VRChat for Quest, and will not show unless a user chooses to show your avatar." + + " See additional warnings for suggestions on how to improve performance. Click 'Avatar Optimization Tips' below for more information.", + AvatarPerformanceStats.GetPerformanceRatingDisplayName(rating)); + } + else + { + text = string.Format( + "Overall Performance: {0} - This avatar does not meet minimum performance requirements for VRChat. " + + "It may be blocked by users depending on their Performance settings." + + " See additional warnings for suggestions on how to improve performance. Click 'Avatar Optimization Tips' below for more information.", + AvatarPerformanceStats.GetPerformanceRatingDisplayName(rating)); + } + + break; + } + } + + break; + } + case AvatarPerformanceCategory.PolyCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + { + displayLevel = PerformanceInfoDisplayLevel.Info; + text = string.Format("Polygons: {0}", perfStats.polyCount); + break; + } + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Info; + text = string.Format("Polygons: {0} (Recommended: {1})", perfStats.polyCount, AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).polyCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Polygons: {0} - Please try to reduce your avatar poly count to less than {1} (Recommended: {2})", + perfStats.polyCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Good).polyCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).polyCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Polygons: {0} - This avatar has too many polygons. " + + (VRC.ValidationHelpers.IsMobilePlatform() + ? "It will be blocked by default on VRChat for Quest, and will not show unless a user chooses to show your avatar." + : "It may be blocked by users depending on their Performance settings.") + + " It should have less than {1}. VRChat recommends having less than {2}.", + perfStats.polyCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).polyCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).polyCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.AABB: + { + switch(rating) + { + case PerformanceRating.Excellent: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Bounding box (AABB) size: {0}", perfStats.aabb.GetValueOrDefault().size.ToString()); + break; + } + case PerformanceRating.Good: + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Bounding box (AABB) size: {0} (Recommended: {1})", + perfStats.aabb.GetValueOrDefault().size.ToString(), + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).aabb.size.ToString()); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "This avatar's bounding box (AABB) is too large on at least one axis. Current size: {0}, Maximum size: {1}", + perfStats.aabb.GetValueOrDefault().size.ToString(), + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).aabb.size.ToString()); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.SkinnedMeshCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Skinned Mesh Renderers: {0}", perfStats.skinnedMeshCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Skinned Mesh Renderers: {0} (Recommended: {1}) - Combine multiple skinned meshes for optimal performance.", + perfStats.skinnedMeshCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).skinnedMeshCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Skinned Mesh Renderers: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many skinned meshes." + + " Combine multiple skinned meshes for optimal performance.", + perfStats.skinnedMeshCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).skinnedMeshCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).skinnedMeshCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.MeshCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Mesh Renderers: {0}", perfStats.meshCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Mesh Renderers: {0} (Recommended: {1}) - Combine multiple meshes for optimal performance.", + perfStats.meshCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).meshCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Mesh Renderers: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many meshes. Combine multiple meshes for optimal performance.", + perfStats.meshCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).meshCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).meshCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.MaterialCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Material Slots: {0}", perfStats.materialCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Material Slots: {0} (Recommended: {1}) - Combine materials and atlas textures for optimal performance.", + perfStats.materialCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).materialCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Material Slots: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many materials. Combine materials and atlas textures for optimal performance.", + perfStats.materialCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).materialCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).materialCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.AnimatorCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Animator Count: {0}", perfStats.animatorCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Animator Count: {0} (Recommended: {1}) - Avoid using extra Animators for optimal performance.", + perfStats.animatorCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).animatorCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Animator Count: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many Animators. Avoid using extra Animators for optimal performance.", + perfStats.animatorCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).animatorCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).animatorCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.BoneCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Bones: {0}", perfStats.boneCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Bones: {0} (Recommended: {1}) - Reduce number of bones for optimal performance.", + perfStats.boneCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).boneCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Bones: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many bones. Reduce number of bones for optimal performance.", + perfStats.boneCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).boneCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).boneCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.LightCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Lights: {0}", perfStats.lightCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Lights: {0} (Recommended: {1}) - Avoid use of dynamic lights for optimal performance.", + perfStats.lightCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).lightCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Lights: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many dynamic lights. Avoid use of dynamic lights for optimal performance.", + perfStats.lightCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).lightCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).lightCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.ParticleSystemCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Particle Systems: {0}", perfStats.particleSystemCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Particle Systems: {0} (Recommended: {1}) - Reduce number of particle systems for better performance.", + perfStats.particleSystemCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).particleSystemCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Particle Systems: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many particle systems." + + " Reduce number of particle systems for better performance.", + perfStats.particleSystemCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).particleSystemCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).particleSystemCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.ParticleTotalCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Total Combined Max Particle Count: {0}", perfStats.particleTotalCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Total Combined Max Particle Count: {0} (Recommended: {1}) - Reduce 'Max Particles' across all particle systems for better performance.", + perfStats.particleTotalCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).particleTotalCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Total Combined Max Particle Count: {0} (Maximum: {1}, Recommended: {2}) - This avatar uses too many particles." + + " Reduce 'Max Particles' across all particle systems for better performance.", + perfStats.particleTotalCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).particleTotalCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).particleTotalCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.ParticleMaxMeshPolyCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Mesh Particle Total Max Poly Count: {0}", perfStats.particleMaxMeshPolyCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Mesh Particle Total Max Poly Count: {0} (Recommended: {1}) - Reduce number of polygons in particle meshes, and reduce 'Max Particles' for better performance.", + perfStats.particleMaxMeshPolyCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).particleMaxMeshPolyCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Mesh Particle Total Max Poly Count: {0} (Maximum: {1}, Recommended: {2}) - This avatar uses too many mesh particle polygons." + + " Reduce number of polygons in particle meshes, and reduce 'Max Particles' for better performance.", + perfStats.particleMaxMeshPolyCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).particleTotalCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).particleMaxMeshPolyCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.ParticleTrailsEnabled: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Particle Trails Enabled: {0}", perfStats.particleTrailsEnabled); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Particle Trails Enabled: {0} (Recommended: {1}) - Avoid particle trails for better performance.", + perfStats.particleTrailsEnabled, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).particleTrailsEnabled); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.ParticleCollisionEnabled: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Particle Collision Enabled: {0}", perfStats.particleCollisionEnabled); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Particle Collision Enabled: {0} (Recommended: {1}) - Avoid particle collision for better performance.", + perfStats.particleCollisionEnabled, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).particleCollisionEnabled); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.TrailRendererCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Trail Renderers: {0}", perfStats.trailRendererCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Trail Renderers: {0} (Recommended: {1}) - Reduce number of TrailRenderers for better performance.", + perfStats.trailRendererCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).trailRendererCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Trail Renderers: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many TrailRenderers. Reduce number of TrailRenderers for better performance.", + perfStats.trailRendererCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).trailRendererCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).trailRendererCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.LineRendererCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Line Renderers: {0}", perfStats.lineRendererCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Line Renderers: {0} (Recommended: {1}) - Reduce number of LineRenderers for better performance.", + perfStats.lineRendererCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).lineRendererCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Line Renderers: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many LineRenderers. Reduce number of LineRenderers for better performance.", + perfStats.lineRendererCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).lineRendererCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).lineRendererCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.DynamicBoneComponentCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Dynamic Bone Components: {0}", perfStats.dynamicBoneComponentCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Dynamic Bone Components: {0} (Recommended: {1}) - Reduce number of DynamicBone components for better performance.", + perfStats.dynamicBoneComponentCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).dynamicBoneComponentCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Dynamic Bone Components: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many DynamicBone components." + + " Reduce number of DynamicBone components for better performance.", + perfStats.dynamicBoneComponentCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).dynamicBoneComponentCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).dynamicBoneComponentCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.DynamicBoneSimulatedBoneCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Dynamic Bone Simulated Bone Count: {0}", perfStats.dynamicBoneSimulatedBoneCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Dynamic Bone Simulated Bone Count: {0} (Recommended: {1}) - " + + "Reduce number of transforms in hierarchy under DynamicBone components, or set EndLength or EndOffset to zero to reduce the number of simulated bones.", + perfStats.dynamicBoneSimulatedBoneCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).dynamicBoneSimulatedBoneCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Dynamic Bone Simulated Bone Count: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many bones simulated by DynamicBone." + + " Reduce number of transforms in hierarchy under DynamicBone components, or set EndLength or EndOffset to zero to reduce the number of simulated bones.", + perfStats.dynamicBoneSimulatedBoneCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).dynamicBoneSimulatedBoneCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).dynamicBoneSimulatedBoneCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.DynamicBoneColliderCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Dynamic Bone Collider Count: {0}", perfStats.dynamicBoneColliderCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Dynamic Bone Collider Count: {0} (Recommended: {1}) - Avoid use of DynamicBoneColliders for better performance.", + perfStats.dynamicBoneColliderCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).dynamicBoneColliderCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Dynamic Bone Collider Count: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many DynamicBoneColliders." + + " Avoid use of DynamicBoneColliders for better performance.", + perfStats.dynamicBoneColliderCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).dynamicBoneColliderCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).dynamicBoneColliderCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.DynamicBoneCollisionCheckCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Dynamic Bone Collision Check Count: {0}", perfStats.dynamicBoneCollisionCheckCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Dynamic Bone Collision Check Count: {0} (Recommended: {1}) - Avoid use of DynamicBoneColliders for better performance.", + perfStats.dynamicBoneCollisionCheckCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).dynamicBoneCollisionCheckCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Dynamic Bone Collision Check Count: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many DynamicBoneColliders." + + " Avoid use of DynamicBoneColliders for better performance.", + perfStats.dynamicBoneCollisionCheckCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).dynamicBoneCollisionCheckCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).dynamicBoneCollisionCheckCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.ClothCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Cloth Component Count: {0}", perfStats.clothCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Cloth Component Count: {0} (Recommended: {1}) - Avoid use of cloth for optimal performance.", + perfStats.clothCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).clothCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Cloth Component Count: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many Cloth components. Avoid use of cloth for optimal performance.", + perfStats.clothCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).clothCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).clothCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.ClothMaxVertices: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Cloth Total Vertex Count: {0}", perfStats.clothMaxVertices); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Cloth Total Vertex Count: {0} (Recommended: {1}) - Reduce number of vertices in cloth meshes for improved performance.", + perfStats.clothMaxVertices, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).clothMaxVertices); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Cloth Total Vertex Count: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many vertices in cloth meshes." + + " Reduce number of vertices in cloth meshes for improved performance.", + perfStats.clothMaxVertices, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).clothMaxVertices, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).clothMaxVertices); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.PhysicsColliderCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Physics Collider Count: {0}", perfStats.physicsColliderCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Physics Collider Count: {0} (Recommended: {1}) - Avoid use of colliders for optimal performance.", + perfStats.physicsColliderCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).physicsColliderCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Physics Collider Count: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many colliders. Avoid use of colliders for optimal performance.", + perfStats.physicsColliderCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).physicsColliderCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).physicsColliderCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.PhysicsRigidbodyCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Physics Rigidbody Count: {0}", perfStats.physicsRigidbodyCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Physics Rigidbody Count: {0} (Recommended: {1}) - Avoid use of rigidbodies for optimal performance.", + perfStats.physicsRigidbodyCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).physicsRigidbodyCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Physics Rigidbody Count: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many rigidbodies. Avoid use of rigidbodies for optimal performance.", + perfStats.physicsRigidbodyCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).physicsRigidbodyCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).physicsRigidbodyCount); + + break; + } + } + + break; + } + case AvatarPerformanceCategory.AudioSourceCount: + { + switch(rating) + { + case PerformanceRating.Excellent: + case PerformanceRating.Good: + { + displayLevel = PerformanceInfoDisplayLevel.Verbose; + text = string.Format("Audio Sources: {0}", perfStats.audioSourceCount); + break; + } + case PerformanceRating.Medium: + case PerformanceRating.Poor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Audio Sources: {0} (Recommended: {1}) - Reduce number of audio sources for better performance.", + perfStats.audioSourceCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).audioSourceCount); + + break; + } + case PerformanceRating.VeryPoor: + { + displayLevel = PerformanceInfoDisplayLevel.Warning; + text = string.Format( + "Audio Sources: {0} (Maximum: {1}, Recommended: {2}) - This avatar has too many audio sources. Reduce number of audio sources for better performance.", + perfStats.audioSourceCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Poor).audioSourceCount, + AvatarPerformanceStats.GetStatLevelForRating(PerformanceRating.Excellent).audioSourceCount); + + break; + } + } + + break; + } + default: + { + text = ""; + displayLevel = PerformanceInfoDisplayLevel.None; + break; + } + } + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Validation/Performance/SDKPerformanceDisplay.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Validation/Performance/SDKPerformanceDisplay.cs.meta new file mode 100644 index 00000000..88aebe1e --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Editor/Validation/Performance/SDKPerformanceDisplay.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 62d40cc4e8f8494695f0102c58b3ea60 +timeCreated: 1564166079
\ No newline at end of file |