浏览代码
Merge pull request #173 from Unity-Technologies/categorical-parameter-fixes
Merge pull request #173 from Unity-Technologies/categorical-parameter-fixes
Fixed and polished a few Randomization UI elements/main
GitHub
4 年前
当前提交
7b0d663a
共有 43 个文件被更改,包括 720 次插入 和 570 次删除
-
12com.unity.perception/CHANGELOG.md
-
67com.unity.perception/Editor/Randomization/Editors/PerceptionEditorAnalytics.cs
-
32com.unity.perception/Editor/Randomization/Editors/RunInUnitySimulationWindow.cs
-
80com.unity.perception/Editor/Randomization/Editors/ScenarioBaseEditor.cs
-
5com.unity.perception/Editor/Randomization/PropertyDrawers/ColorHsvaDrawer.cs
-
4com.unity.perception/Editor/Randomization/PropertyDrawers/ParameterDrawer.cs
-
1com.unity.perception/Editor/Randomization/Uxml/Sampler/FloatRangeElement.uxml
-
7com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerElement.uxml
-
4com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerElement.uxml.meta
-
20com.unity.perception/Editor/Randomization/VisualElements/Parameter/CategoricalOptionElement.cs
-
9com.unity.perception/Editor/Randomization/VisualElements/Parameter/ColorHsvaField.cs
-
37com.unity.perception/Editor/Randomization/VisualElements/Parameter/DrawerParameterElement.cs
-
88com.unity.perception/Editor/Randomization/VisualElements/Parameter/ParameterElement.cs
-
166com.unity.perception/Editor/Randomization/VisualElements/Randomizer/AddRandomizerMenu.cs
-
12com.unity.perception/Editor/Randomization/VisualElements/Randomizer/DragToReorderManipulator.cs
-
72com.unity.perception/Editor/Randomization/VisualElements/Randomizer/RandomizerElement.cs
-
34com.unity.perception/Editor/Randomization/VisualElements/Randomizer/RandomizerList.cs
-
5com.unity.perception/Editor/Randomization/VisualElements/Randomizer/RandomizerReorderingIndicator.cs
-
6com.unity.perception/Editor/Randomization/VisualElements/Sampler/FloatRangeElement.cs
-
120com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerElement.cs
-
14com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerElement.cs.meta
-
12com.unity.perception/Runtime/Randomization/Parameters/CategoricalParameter.cs
-
2com.unity.perception/Runtime/Randomization/Randomizers/Randomizer.cs
-
2com.unity.perception/Runtime/Randomization/Samplers/ISampler.cs
-
10com.unity.perception/Tests/Runtime/Randomization/ParameterTests/CategoricalParameterTests.cs
-
26com.unity.perception/Editor/Randomization/PropertyDrawers/FloatRangeDrawer.cs
-
3com.unity.perception/Editor/Randomization/PropertyDrawers/FloatRangeDrawer.cs.meta
-
28com.unity.perception/Editor/Randomization/PropertyDrawers/SamplerDrawer.cs
-
3com.unity.perception/Editor/Randomization/PropertyDrawers/SamplerDrawer.cs.meta
-
10com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerInterfaceElement.uxml
-
3com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerInterfaceElement.uxml.meta
-
89com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerInterfaceElement.cs
-
11com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerInterfaceElement.cs.meta
-
22com.unity.perception/Editor/Randomization/Utilities/ParameterUIElementsEditor.cs
-
95com.unity.perception/Editor/Randomization/Utilities/StaticData.cs
-
75com.unity.perception/Editor/Randomization/Utilities/UIElementsEditorUtilities.cs
-
3com.unity.perception/Editor/Randomization/Utilities/UIElementsEditorUtilities.cs.meta
-
101com.unity.perception/Editor/Randomization/StaticData.cs
-
0/com.unity.perception/Editor/Randomization/Utilities/StaticData.cs.meta
-
0/com.unity.perception/Editor/Randomization/Utilities.meta
-
0/com.unity.perception/Editor/Randomization/Utilities/ParameterUIElementsEditor.cs.meta
|
|||
<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements"> |
|||
<VisualElement name="sampler-template" style="margin-bottom: 4px;"> |
|||
<VisualElement style="margin-bottom: 4px;"> |
|||
<VisualElement style="flex-direction: row; align-items: center;"> |
|||
<Label name="sampler-name" text="Sampler Name" class="unity-base-field__label"/> |
|||
<editor:ToolbarMenu name="sampler-type-dropdown" text="Placeholder Sampler Type" class="sampler__type-menu"/> |
|||
</VisualElement> |
|||
<Label name="display-name" text="Sampler Name" class="unity-base-field__label"/> |
|||
<VisualElement name="fields-container" style="margin-left: 18px;"/> |
|||
</VisualElement> |
|||
</UXML> |
|
|||
fileFormatVersion: 2 |
|||
guid: e91be9c80e944358b231c125be80a749 |
|||
timeCreated: 1594847524 |
|||
guid: a4752f9d99d8497e9a147942da225b5f |
|||
timeCreated: 1612043461 |
|
|||
using System; |
|||
using System.Linq; |
|||
using UnityEditor; |
|||
using UnityEditor.UIElements; |
|||
using UnityEngine.Experimental.Perception.Randomization.Parameters; |
|||
using UnityEngine.Experimental.Perception.Randomization.Samplers; |
|||
namespace UnityEngine.Experimental.Perception.Randomization.Editor |
|||
namespace UnityEditor.Experimental.Perception.Randomization |
|||
Parameter m_Parameter; |
|||
ISampler m_Sampler; |
|||
SerializedProperty m_Property; |
|||
SerializedProperty m_RangeProperty; |
|||
VisualElement m_Properties; |
|||
ToolbarMenu m_SamplerTypeDropdown; |
|||
|
|||
public SamplerElement(SerializedProperty property, Parameter parameter) |
|||
public SamplerElement(SerializedProperty property) |
|||
m_Property = property; |
|||
m_Parameter = parameter; |
|||
m_Sampler = GetSamplerFromSerializedObject(); |
|||
|
|||
if (m_Sampler == null) |
|||
CreateSampler(typeof(UniformSampler)); |
|||
|
|||
var samplerName = this.Q<Label>("sampler-name"); |
|||
samplerName.text = UppercaseFirstLetter(m_Property.name); |
|||
|
|||
m_Properties = this.Q<VisualElement>("fields-container"); |
|||
m_SamplerTypeDropdown = this.Q<ToolbarMenu>("sampler-type-dropdown"); |
|||
m_SamplerTypeDropdown.text = SamplerUtility.GetSamplerDisplayName(m_Sampler.GetType());; |
|||
foreach (var samplerType in StaticData.samplerTypes) |
|||
{ |
|||
var displayName = SamplerUtility.GetSamplerDisplayName(samplerType);; |
|||
m_SamplerTypeDropdown.menu.AppendAction( |
|||
displayName, |
|||
a => { ReplaceSampler(samplerType); }, |
|||
a => DropdownMenuAction.Status.Normal); |
|||
} |
|||
CreatePropertyFields(); |
|||
} |
|||
|
|||
void ReplaceSampler(Type samplerType) |
|||
{ |
|||
CreateSampler(samplerType); |
|||
m_SamplerTypeDropdown.text = SamplerUtility.GetSamplerDisplayName(samplerType); |
|||
CreatePropertyFields(); |
|||
} |
|||
|
|||
void CreateSampler(Type samplerType) |
|||
{ |
|||
var newSampler = (ISampler)Activator.CreateInstance(samplerType); |
|||
CopyFloatRangeToNewSampler(newSampler); |
|||
m_Sampler = newSampler; |
|||
m_Property.managedReferenceValue = newSampler; |
|||
m_Property.serializedObject.ApplyModifiedProperties(); |
|||
} |
|||
|
|||
void CopyFloatRangeToNewSampler(ISampler newSampler) |
|||
{ |
|||
if (m_RangeProperty == null) |
|||
return; |
|||
|
|||
var rangeField = newSampler.GetType().GetField(m_RangeProperty.name); |
|||
if (rangeField == null) |
|||
return; |
|||
|
|||
var range = new FloatRange( |
|||
m_RangeProperty.FindPropertyRelative("minimum").floatValue, |
|||
m_RangeProperty.FindPropertyRelative("maximum").floatValue); |
|||
rangeField.SetValue(newSampler, range); |
|||
} |
|||
|
|||
void CreatePropertyFields() |
|||
{ |
|||
m_RangeProperty = null; |
|||
m_Properties.Clear(); |
|||
var currentProperty = m_Property.Copy(); |
|||
var nextSiblingProperty = m_Property.Copy(); |
|||
nextSiblingProperty.NextVisible(false); |
|||
|
|||
if (currentProperty.NextVisible(true)) |
|||
{ |
|||
do |
|||
{ |
|||
if (SerializedProperty.EqualContents(currentProperty, nextSiblingProperty)) |
|||
break; |
|||
if (currentProperty.type == "FloatRange") |
|||
{ |
|||
m_RangeProperty = currentProperty.Copy(); |
|||
m_Properties.Add(new FloatRangeElement(m_RangeProperty)); |
|||
} |
|||
else |
|||
{ |
|||
var propertyField = new PropertyField(currentProperty.Copy()); |
|||
propertyField.Bind(m_Property.serializedObject); |
|||
var originalField = m_Sampler.GetType().GetField(currentProperty.name); |
|||
var tooltipAttribute = originalField.GetCustomAttributes(true).ToList().Find(att => att.GetType() == typeof(TooltipAttribute)); |
|||
if (tooltipAttribute != null) |
|||
{ |
|||
propertyField.tooltip = (tooltipAttribute as TooltipAttribute)?.tooltip; |
|||
} |
|||
m_Properties.Add(propertyField); |
|||
} |
|||
} |
|||
while (currentProperty.NextVisible(false)); |
|||
} |
|||
} |
|||
var displayName = this.Q<Label>("display-name"); |
|||
displayName.text = property.displayName; |
|||
static string UppercaseFirstLetter(string s) |
|||
{ |
|||
return string.IsNullOrEmpty(s) ? string.Empty : char.ToUpper(s[0]) + s.Substring(1); |
|||
} |
|||
|
|||
ISampler GetSamplerFromSerializedObject() |
|||
{ |
|||
var configType = m_Parameter.GetType(); |
|||
var field = configType.GetField(m_Property.name); |
|||
return (ISampler)field.GetValue(m_Parameter); |
|||
var fieldsContainer = this.Q<VisualElement>("fields-container"); |
|||
UIElementsEditorUtilities.CreatePropertyFields(property, fieldsContainer); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 134b50014b9f4c0694a087d3529ea4c2 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|||
fileFormatVersion: 2 |
|||
guid: a5920440efa84756a581dda95394a14f |
|||
timeCreated: 1612042675 |
|
|||
using System; |
|||
using UnityEngine; |
|||
using UnityEngine.Experimental.Perception.Randomization.Samplers; |
|||
using UnityEngine.UIElements; |
|||
|
|||
namespace UnityEditor.Experimental.Perception.Randomization.PropertyDrawers |
|||
{ |
|||
[CustomPropertyDrawer(typeof(FloatRange))] |
|||
class FloatRangeDrawer : PropertyDrawer |
|||
{ |
|||
public override VisualElement CreatePropertyGUI(SerializedProperty property) |
|||
{ |
|||
return new FloatRangeElement(property); |
|||
} |
|||
|
|||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) |
|||
{ |
|||
EditorGUI.PropertyField(position, property, label, true); |
|||
} |
|||
|
|||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) |
|||
{ |
|||
return EditorGUI.GetPropertyHeight(property); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 2aaf69aad9c844a592283d36b3c14d8f |
|||
timeCreated: 1612042769 |
|
|||
using System; |
|||
using UnityEngine; |
|||
using UnityEngine.Experimental.Perception.Randomization.Samplers; |
|||
using UnityEngine.UIElements; |
|||
|
|||
namespace UnityEditor.Experimental.Perception.Randomization.PropertyDrawers |
|||
{ |
|||
[CustomPropertyDrawer(typeof(ISampler), true)] |
|||
class SamplerDrawer : PropertyDrawer |
|||
{ |
|||
public override VisualElement CreatePropertyGUI(SerializedProperty property) |
|||
{ |
|||
return fieldInfo.FieldType.IsInterface |
|||
? new SamplerInterfaceElement(property) as VisualElement |
|||
: new SamplerElement(property); |
|||
} |
|||
|
|||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) |
|||
{ |
|||
EditorGUI.PropertyField(position, property, label, true); |
|||
} |
|||
|
|||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) |
|||
{ |
|||
return EditorGUI.GetPropertyHeight(property); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 87021ed3ca1241f8953af2ee975504c4 |
|||
timeCreated: 1612040428 |
|
|||
<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements"> |
|||
<VisualElement name="sampler-template" style="margin-bottom: 4px;"> |
|||
<Style src="../../Uss/Styles.uss"/> |
|||
<VisualElement style="flex-direction: row; align-items: center;"> |
|||
<Label name="sampler-name" text="Sampler Name" class="unity-base-field__label"/> |
|||
<editor:ToolbarMenu name="sampler-type-dropdown" text="Placeholder Sampler Type" class="sampler__type-menu"/> |
|||
</VisualElement> |
|||
<VisualElement name="fields-container" style="margin-left: 18px;"/> |
|||
</VisualElement> |
|||
</UXML> |
|
|||
fileFormatVersion: 2 |
|||
guid: e91be9c80e944358b231c125be80a749 |
|||
timeCreated: 1594847524 |
|
|||
using System; |
|||
using UnityEditor.UIElements; |
|||
using UnityEngine.Experimental.Perception.Randomization.Samplers; |
|||
using UnityEngine.UIElements; |
|||
|
|||
namespace UnityEditor.Experimental.Perception.Randomization |
|||
{ |
|||
class SamplerInterfaceElement : VisualElement |
|||
{ |
|||
VisualElement m_PropertiesContainer; |
|||
SerializedProperty m_Property; |
|||
SerializedProperty m_RangeProperty; |
|||
ToolbarMenu m_SamplerTypeDropdown; |
|||
|
|||
public SamplerInterfaceElement(SerializedProperty property) |
|||
{ |
|||
m_Property = property; |
|||
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>( |
|||
$"{StaticData.uxmlDir}/Sampler/SamplerInterfaceElement.uxml"); |
|||
template.CloneTree(this); |
|||
|
|||
if (sampler == null) |
|||
CreateSampler(typeof(UniformSampler)); |
|||
|
|||
var samplerName = this.Q<Label>("sampler-name"); |
|||
samplerName.text = UppercaseFirstLetter(m_Property.name); |
|||
|
|||
m_PropertiesContainer = this.Q<VisualElement>("fields-container"); |
|||
m_SamplerTypeDropdown = this.Q<ToolbarMenu>("sampler-type-dropdown"); |
|||
m_SamplerTypeDropdown.text = SamplerUtility.GetSamplerDisplayName(sampler.GetType()); |
|||
; |
|||
foreach (var samplerType in StaticData.samplerTypes) |
|||
{ |
|||
var displayName = SamplerUtility.GetSamplerDisplayName(samplerType); |
|||
; |
|||
m_SamplerTypeDropdown.menu.AppendAction( |
|||
displayName, |
|||
a => { ReplaceSampler(samplerType); }, |
|||
a => DropdownMenuAction.Status.Normal); |
|||
} |
|||
|
|||
CreatePropertyFields(); |
|||
} |
|||
|
|||
ISampler sampler => (ISampler)StaticData.GetManagedReferenceValue(m_Property); |
|||
|
|||
void ReplaceSampler(Type samplerType) |
|||
{ |
|||
CreateSampler(samplerType); |
|||
m_SamplerTypeDropdown.text = SamplerUtility.GetSamplerDisplayName(samplerType); |
|||
CreatePropertyFields(); |
|||
} |
|||
|
|||
void CreateSampler(Type samplerType) |
|||
{ |
|||
var newSampler = (ISampler)Activator.CreateInstance(samplerType); |
|||
CopyFloatRangeToNewSampler(newSampler); |
|||
m_Property.managedReferenceValue = newSampler; |
|||
m_Property.serializedObject.ApplyModifiedProperties(); |
|||
} |
|||
|
|||
void CopyFloatRangeToNewSampler(ISampler newSampler) |
|||
{ |
|||
if (m_RangeProperty == null) |
|||
return; |
|||
|
|||
var rangeField = newSampler.GetType().GetField(m_RangeProperty.name); |
|||
if (rangeField == null) |
|||
return; |
|||
|
|||
var range = new FloatRange( |
|||
m_RangeProperty.FindPropertyRelative("minimum").floatValue, |
|||
m_RangeProperty.FindPropertyRelative("maximum").floatValue); |
|||
rangeField.SetValue(newSampler, range); |
|||
} |
|||
|
|||
void CreatePropertyFields() |
|||
{ |
|||
m_RangeProperty = null; |
|||
m_PropertiesContainer.Clear(); |
|||
UIElementsEditorUtilities.CreatePropertyFields(m_Property, m_PropertiesContainer); |
|||
} |
|||
|
|||
static string UppercaseFirstLetter(string s) |
|||
{ |
|||
return string.IsNullOrEmpty(s) ? string.Empty : char.ToUpper(s[0]) + s.Substring(1); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 134b50014b9f4c0694a087d3529ea4c2 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using UnityEngine; |
|||
using UnityEngine.UIElements; |
|||
|
|||
namespace UnityEditor.Experimental.Perception.Randomization |
|||
{ |
|||
/// <summary>
|
|||
/// Derive this class to force the Unity Editor to render the default inspector using UIElements for an Object that
|
|||
/// includes a Parameter field.
|
|||
/// to allow parameter UIs to render properly
|
|||
/// </summary>
|
|||
public abstract class ParameterUIElementsEditor : Editor |
|||
{ |
|||
///<inheritdoc/>
|
|||
public override VisualElement CreateInspectorGUI() |
|||
{ |
|||
var rootElement = new VisualElement(); |
|||
UIElementsEditorUtilities.CreatePropertyFields(serializedObject, rootElement); |
|||
return rootElement; |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using UnityEngine.Experimental.Perception.Randomization.Randomizers; |
|||
using UnityEngine.Experimental.Perception.Randomization.Samplers; |
|||
|
|||
namespace UnityEditor.Experimental.Perception.Randomization |
|||
{ |
|||
static class StaticData |
|||
{ |
|||
const string k_RandomizationDir = "Packages/com.unity.perception/Editor/Randomization"; |
|||
internal const string uxmlDir = k_RandomizationDir + "/Uxml"; |
|||
|
|||
internal static Type[] randomizerTypes; |
|||
internal static Type[] samplerTypes; |
|||
|
|||
static StaticData() |
|||
{ |
|||
randomizerTypes = GetConstructableDerivedTypes<Randomizer>(); |
|||
samplerTypes = GetConstructableDerivedTypes<ISampler>(); |
|||
} |
|||
|
|||
static Type[] GetConstructableDerivedTypes<T>() |
|||
{ |
|||
var collection = TypeCache.GetTypesDerivedFrom<T>(); |
|||
var types = new List<Type>(); |
|||
foreach (var type in collection) |
|||
if (!type.IsAbstract && !type.IsInterface) |
|||
types.Add(type); |
|||
return types.ToArray(); |
|||
} |
|||
|
|||
public static object GetManagedReferenceValue(SerializedProperty prop, bool parent = false) |
|||
{ |
|||
var path = prop.propertyPath.Replace(".Array.data[", "["); |
|||
object obj = prop.serializedObject.targetObject; |
|||
var elements = path.Split('.'); |
|||
if (parent) |
|||
elements = elements.Take(elements.Count() - 1).ToArray(); |
|||
|
|||
foreach (var element in elements) |
|||
if (element.Contains("[")) |
|||
{ |
|||
var elementName = element.Substring(0, element.IndexOf("[")); |
|||
var index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[", "").Replace("]", "")); |
|||
obj = GetArrayValue(obj, elementName, index); |
|||
} |
|||
else |
|||
{ |
|||
obj = GetValue(obj, element); |
|||
} |
|||
|
|||
return obj; |
|||
} |
|||
|
|||
static object GetValue(object source, string name) |
|||
{ |
|||
if (source == null) |
|||
return null; |
|||
var type = source.GetType(); |
|||
var f = type.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); |
|||
if (f == null) |
|||
{ |
|||
var p = type.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); |
|||
return p == null ? null : p.GetValue(source, null); |
|||
} |
|||
|
|||
return f.GetValue(source); |
|||
} |
|||
|
|||
static object GetArrayValue(object source, string name, int index) |
|||
{ |
|||
var value = GetValue(source, name); |
|||
if (!(value is IEnumerable enumerable)) |
|||
return null; |
|||
var enumerator = enumerable.GetEnumerator(); |
|||
while (index-- >= 0) |
|||
enumerator.MoveNext(); |
|||
return enumerator.Current; |
|||
} |
|||
|
|||
public static bool IsSubclassOfRawGeneric(Type generic, Type toCheck) |
|||
{ |
|||
while (toCheck != null && toCheck != typeof(object)) |
|||
{ |
|||
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck; |
|||
if (generic == cur) return true; |
|||
toCheck = toCheck.BaseType; |
|||
} |
|||
return false; |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using System.Linq; |
|||
using UnityEditor.UIElements; |
|||
using UnityEngine; |
|||
using UnityEngine.UIElements; |
|||
|
|||
namespace UnityEditor.Experimental.Perception.Randomization |
|||
{ |
|||
/// <summary>
|
|||
/// This class contains a set of helper functions for simplifying the creation of UI Elements editors
|
|||
/// </summary>
|
|||
public static class UIElementsEditorUtilities |
|||
{ |
|||
/// <summary>
|
|||
/// Creates a list of PropertyFields from the class fields of the given SerializedObject
|
|||
/// and adds them to the specified container element
|
|||
/// </summary>
|
|||
/// <param name="serializedObj">The SerializedObject to create property fields for</param>
|
|||
/// <param name="containerElement">The element to place the created PropertyFields in</param>
|
|||
public static void CreatePropertyFields(SerializedObject serializedObj, VisualElement containerElement) |
|||
{ |
|||
var fieldType = serializedObj.targetObject.GetType(); |
|||
var iterator = serializedObj.GetIterator(); |
|||
iterator.NextVisible(true); |
|||
iterator.NextVisible(false); |
|||
do |
|||
{ |
|||
var propertyField = CreatePropertyField(iterator, fieldType); |
|||
containerElement.Add(propertyField); |
|||
} while (iterator.NextVisible(false)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a list of PropertyFields from the sub-fields of the given SerializedProperty
|
|||
/// and adds them to the specified container element
|
|||
/// </summary>
|
|||
/// <param name="property">The SerializedProperty to create sub property fields for</param>
|
|||
/// <param name="containerElement">The element to place the created PropertyFields in</param>
|
|||
public static void CreatePropertyFields(SerializedProperty property, VisualElement containerElement) |
|||
{ |
|||
var fieldType = StaticData.GetManagedReferenceValue(property).GetType(); |
|||
|
|||
var iterator = property.Copy(); |
|||
var nextSiblingProperty = property.Copy(); |
|||
nextSiblingProperty.NextVisible(false); |
|||
|
|||
if (iterator.NextVisible(true)) |
|||
do |
|||
{ |
|||
if (SerializedProperty.EqualContents(iterator, nextSiblingProperty)) |
|||
break; |
|||
var propertyField = CreatePropertyField(iterator, fieldType); |
|||
containerElement.Add(propertyField); |
|||
} while (iterator.NextVisible(false)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a PropertyField from a given SerializedProperty (with tooltips!)
|
|||
/// </summary>
|
|||
/// <param name="iterator">The SerializedProperty to create a PropertyField</param>
|
|||
/// <param name="parentPropertyType">The Type of the class encapsulating the provided SerializedProperty</param>
|
|||
/// <returns></returns>
|
|||
public static PropertyField CreatePropertyField(SerializedProperty iterator, Type parentPropertyType) |
|||
{ |
|||
var propertyField = new PropertyField(iterator.Copy()); |
|||
propertyField.Bind(iterator.serializedObject); |
|||
var originalField = parentPropertyType.GetField(iterator.name); |
|||
var tooltipAttribute = originalField.GetCustomAttributes(true) |
|||
.ToList().Find(att => att.GetType() == typeof(TooltipAttribute)); |
|||
if (tooltipAttribute != null) |
|||
propertyField.tooltip = (tooltipAttribute as TooltipAttribute)?.tooltip; |
|||
return propertyField; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 9ed5513847d3486dbf017c9fb30186b9 |
|||
timeCreated: 1612048047 |
|
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using UnityEditor; |
|||
using UnityEngine.Experimental.Perception.Randomization.Parameters; |
|||
using UnityEngine.Experimental.Perception.Randomization.Randomizers; |
|||
using UnityEngine.Experimental.Perception.Randomization.Samplers; |
|||
|
|||
namespace UnityEngine.Experimental.Perception.Randomization.Editor |
|||
{ |
|||
static class StaticData |
|||
{ |
|||
const string k_RandomizationDir = "Packages/com.unity.perception/Editor/Randomization"; |
|||
internal const string uxmlDir = k_RandomizationDir + "/Uxml"; |
|||
|
|||
internal static readonly string samplerSerializedFieldType; |
|||
|
|||
internal static Type[] randomizerTypes; |
|||
internal static Type[] samplerTypes; |
|||
|
|||
static StaticData() |
|||
{ |
|||
randomizerTypes = GetConstructableDerivedTypes<Randomizer>(); |
|||
samplerTypes = GetConstructableDerivedTypes<ISampler>(); |
|||
var samplerType = typeof(ISampler); |
|||
samplerSerializedFieldType = $"{samplerType.Assembly.GetName().Name} {samplerType.FullName}"; |
|||
} |
|||
|
|||
static Type[] GetConstructableDerivedTypes<T>() |
|||
{ |
|||
var collection = TypeCache.GetTypesDerivedFrom<T>(); |
|||
var types = new List<Type>(); |
|||
foreach (var type in collection) |
|||
{ |
|||
if (!type.IsAbstract && !type.IsInterface) |
|||
types.Add(type); |
|||
} |
|||
return types.ToArray(); |
|||
} |
|||
|
|||
internal static object GetManagedReferenceValue(SerializedProperty prop, bool parent=false) |
|||
{ |
|||
var path = prop.propertyPath.Replace(".Array.data[", "["); |
|||
object obj = prop.serializedObject.targetObject; |
|||
var elements = path.Split('.'); |
|||
if (parent) |
|||
elements = elements.Take(elements.Count() - 1).ToArray(); |
|||
|
|||
foreach (var element in elements) |
|||
{ |
|||
if (element.Contains("[")) |
|||
{ |
|||
var elementName = element.Substring(0, element.IndexOf("[")); |
|||
var index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[","").Replace("]","")); |
|||
obj = GetArrayValue(obj, elementName, index); |
|||
} |
|||
else |
|||
obj = GetValue(obj, element); |
|||
} |
|||
return obj; |
|||
} |
|||
|
|||
static object GetValue(object source, string name) |
|||
{ |
|||
if (source == null) |
|||
return null; |
|||
var type = source.GetType(); |
|||
var f = type.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); |
|||
if (f == null) |
|||
{ |
|||
var p = type.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); |
|||
return p == null ? null : p.GetValue(source, null); |
|||
} |
|||
return f.GetValue(source); |
|||
} |
|||
|
|||
static object GetArrayValue(object source, string name, int index) |
|||
{ |
|||
var value = GetValue(source, name); |
|||
if (!(value is IEnumerable enumerable)) |
|||
return null; |
|||
var enumerator = enumerable.GetEnumerator(); |
|||
while (index-- >= 0) |
|||
enumerator.MoveNext(); |
|||
return enumerator.Current; |
|||
} |
|||
|
|||
public static bool IsSubclassOfRawGeneric(Type generic, Type toCheck) { |
|||
while (toCheck != null && toCheck != typeof(object)) { |
|||
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck; |
|||
if (generic == cur) { |
|||
return true; |
|||
} |
|||
toCheck = toCheck.BaseType; |
|||
} |
|||
return false; |
|||
} |
|||
} |
|||
} |
撰写
预览
正在加载...
取消
保存
Reference in new issue