Example #1
0
        protected override bool Initialize()
        {
            var rb = RigidBody?.GetInitialized <RigidBody>()?.Native;

            if (rb == null)
            {
                Debug.LogWarning("Unable to find RigidBody component for DeformableTerrainShovel - shovel instance ignored.", this);
                return(false);
            }

            if (!TopEdge.Valid)
            {
                Debug.LogWarning("Unable to create shovel - invalid Top Edge.", this);
            }
            if (!CuttingEdge.Valid)
            {
                Debug.LogWarning("Unable to create shovel - invalid Cutting Edge.", this);
            }
            if (!CuttingDirection.Valid)
            {
                Debug.LogWarning("Unable to create shovel - invalid Cutting Direction.", this);
            }

            if (!HasValidateEdges())
            {
                return(false);
            }

            Native = new agxTerrain.Shovel(rb,
                                           TopEdge.ToNativeEdge(gameObject),
                                           CuttingEdge.ToNativeEdge(gameObject),
                                           CuttingDirection.CalculateLocalDirection(gameObject).ToHandedVec3());

            if (Settings == null)
            {
                Settings      = ScriptAsset.Create <DeformableTerrainShovelSettings>();
                Settings.name = "[Temporary]Shovel Settings";
            }

            return(true);
        }
Example #2
0
        public static T Create <T>(string name) where T : ScriptAsset
        {
            string path = Selection.activeObject == null ? "Assets" : AssetDatabase.GetAssetPath(Selection.activeObject);

            if (System.IO.Path.GetExtension(path) != "")
            {
                Debug.Log("Not valid to create asset in an asset that isn't a folder.");
                return(null);
            }

            T asset = ScriptAsset.Create <T>();

            string pathAndName = AssetDatabase.GenerateUniqueAssetPath(path + "/" + name + ".asset");

            AssetDatabase.CreateAsset(asset, pathAndName);

            AssetDatabase.SaveAssets();
            EditorUtility.FocusProjectWindow();
            Selection.activeObject = asset;

            return(asset);
        }
Example #3
0
        private TwoBodyTireProperties GetOrCreateTireModelProperties()
        {
            if (m_tireProperties != null)
            {
                return(m_tireProperties);
            }

            m_tireProperties = ScriptAsset.Create <TwoBodyTireProperties>();
            m_tireProperties.RadialStiffness             = 2.0E6f;
            m_tireProperties.RadialDampingCoefficient    = 9.0E4f;
            m_tireProperties.LateralStiffness            = 4.0E6f;
            m_tireProperties.LateralDampingCoefficient   = 9.0E4f;
            m_tireProperties.BendingStiffness            = 1.0E6f;
            m_tireProperties.BendingDampingCoefficient   = 9.0E4f;
            m_tireProperties.TorsionalStiffness          = 1.0E6f;
            m_tireProperties.TorsionalDampingCoefficient = 9.0E4f;

            LeftRearTireModel.Properties   = m_tireProperties;
            RightRearTireModel.Properties  = m_tireProperties;
            LeftFrontTireModel.Properties  = m_tireProperties;
            RightFrontTireModel.Properties = m_tireProperties;

            return(m_tireProperties);
        }
Example #4
0
        private void Generate(Node node)
        {
            if (node == null)
            {
                return;
            }

            // TODO: Skip if node.GameObject != null means "use Unity configuration".

            switch (node.Type)
            {
            case Node.NodeType.Assembly:
                agx.Frame frame = m_tree.GetAssembly(node.Uuid);
                node.GameObject      = GetOrCreateGameObject(node);
                node.GameObject.name = FindName("", node.Type.ToString());

                node.GameObject.transform.position = frame.getTranslate().ToHandedVector3();
                node.GameObject.transform.rotation = frame.getRotate().ToHandedQuaternion();

                node.GameObject.GetOrCreateComponent <Assembly>();

                break;

            case Node.NodeType.RigidBody:
                agx.RigidBody nativeRb = m_tree.GetRigidBody(node.Uuid);
                node.GameObject      = GetOrCreateGameObject(node);
                node.GameObject.name = FindName(nativeRb.getName(), node.Type.ToString());


                node.GameObject.transform.position = nativeRb.getPosition().ToHandedVector3();
                node.GameObject.transform.rotation = nativeRb.getRotation().ToHandedQuaternion();

                node.GameObject.GetOrCreateComponent <RigidBody>().RestoreLocalDataFrom(nativeRb);


                break;

            case Node.NodeType.Geometry:
                // Ignoring geometries - handling Shape == Geometry.
                // The shapes are children to this node.
                break;

            case Node.NodeType.Shape:
                var nativeGeometry  = m_tree.GetGeometry(node.Parent.Uuid);
                var nativeShape     = m_tree.GetShape(node.Uuid);
                var nativeShapeType = (agxCollide.Shape.Type)nativeShape.getType();

                node.GameObject      = GetOrCreateGameObject(node);
                node.GameObject.name = FindName(nativeGeometry.getName() +
                                                "_" +
                                                nativeShapeType.ToString().ToLower().FirstCharToUpperCase(),
                                                node.Type.ToString());

                node.GameObject.transform.position = nativeShape.getTransform().getTranslate().ToHandedVector3();
                node.GameObject.transform.rotation = nativeShape.getTransform().getRotate().ToHandedQuaternion();

                if (!CreateShape(node))
                {
                    GameObject.DestroyImmediate(node.GameObject);
                }

                break;

            case Node.NodeType.Material:
                var nativeMaterial = m_tree.GetMaterial(node.Uuid);
                node.Asset      = ScriptAsset.Create <ShapeMaterial>().RestoreLocalDataFrom(nativeMaterial);
                node.Asset.name = FindName(nativeMaterial.getName(), node.Type.ToString());

                node.Asset = AddOrReplaceAsset(node.Asset as ShapeMaterial, node, AGXUnity.IO.AssetType.ShapeMaterial);

                break;

            case Node.NodeType.ContactMaterial:
                var nativeContactMaterial = m_tree.GetContactMaterial(node.Uuid);
                var nativeFrictionModel   = nativeContactMaterial.getFrictionModel();

                var contactMaterial = ScriptAsset.Create <ContactMaterial>().RestoreLocalDataFrom(nativeContactMaterial);
                contactMaterial.name = FindName("ContactMaterial_" +
                                                nativeContactMaterial.getMaterial1().getName() +
                                                "_" +
                                                nativeContactMaterial.getMaterial2().getName(),
                                                node.Type.ToString());

                var materials = node.GetReferences(Node.NodeType.Material);
                if (materials.Length == 0)
                {
                    Debug.LogWarning("No materials referenced to ContactMaterial node.");
                }
                else if (materials.Length == 1)
                {
                    contactMaterial.Material1 = contactMaterial.Material2 = materials[0].Asset as ShapeMaterial;
                }
                else if (materials.Length > 1)
                {
                    contactMaterial.Material1 = materials[0].Asset as ShapeMaterial;
                    contactMaterial.Material2 = materials[1].Asset as ShapeMaterial;
                    if (materials.Length > 2)
                    {
                        Debug.LogWarning("More than two materials referenced to ContactMaterial (" + node.Asset.name + "). First two are used.");
                    }
                }

                if (nativeFrictionModel != null)
                {
                    var frictionModelAsset = ScriptAsset.Create <FrictionModel>().RestoreLocalDataFrom(nativeFrictionModel);
                    frictionModelAsset.name       = "FrictionModel_" + contactMaterial.name;
                    contactMaterial.FrictionModel = AddOrReplaceAsset(frictionModelAsset, node, AGXUnity.IO.AssetType.FrictionModel);
                }

                node.Asset = contactMaterial = AddOrReplaceAsset(contactMaterial, node, AGXUnity.IO.AssetType.ContactMaterial);

                break;

            case Node.NodeType.Constraint:
                var nativeConstraint = m_tree.GetConstraint(node.Uuid);

                node.GameObject      = GetOrCreateGameObject(node);
                node.GameObject.name = FindName(nativeConstraint.getName(),
                                                "AGXUnity." + Constraint.FindType(nativeConstraint));

                if (!CreateConstraint(node))
                {
                    GameObject.DestroyImmediate(node.GameObject);
                }

                break;

            case Node.NodeType.Wire:
                var nativeWire = m_tree.GetWire(node.Uuid);

                node.GameObject      = GetOrCreateGameObject(node);
                node.GameObject.name = FindName(nativeWire.getName(), "AGXUnity.Wire");

                if (!CreateWire(node))
                {
                    GameObject.DestroyImmediate(node.GameObject);
                }

                break;

            case Node.NodeType.Cable:
                var nativeCable = m_tree.GetCable(node.Uuid);

                node.GameObject      = GetOrCreateGameObject(node);
                node.GameObject.name = FindName(nativeCable.getName(), "AGXUnity.Cable");

                if (!CreateCable(node))
                {
                    GameObject.DestroyImmediate(node.GameObject);
                }

                break;
            }

            foreach (var child in node.Children)
            {
                Generate(child);
            }
        }
Example #5
0
        public static object ScriptDrawer(object obj, InvokeWrapper wrapper, GUISkin skin)
        {
            object result           = null;
            var    type             = wrapper.GetContainingType();
            bool   allowSceneObject = type == typeof(GameObject) ||
                                      type.BaseType == typeof(ScriptComponent);
            Object valInField           = wrapper.Get <Object>(obj);
            bool   recursiveEditing     = wrapper.HasAttribute <AllowRecursiveEditing>();
            bool   createNewAssetButton = false;

            if (recursiveEditing)
            {
                var foldoutData = EditorData.Instance.GetData(obj as Object, wrapper.Member.Name);

                GUILayout.BeginHorizontal();
                {
                    var objFieldLabel = MakeLabel(wrapper.Member);
                    var buttonSize    = skin.label.CalcHeight(objFieldLabel, Screen.width);
                    UnityEngine.GUI.enabled = valInField != null;
                    foldoutData.Bool        = GUILayout.Button(GUI.MakeLabel(foldoutData.Bool ? "-" : "+"),
                                                               skin.button,
                                                               new GUILayoutOption[] { GUILayout.Width(20.0f), GUILayout.Height(buttonSize) }) ?
                                              // Button clicked - toggle current value.
                                              !foldoutData.Bool :
                                              // If foldout were enabled but valInField has changed to null - foldout will become disabled.
                                              valInField != null && foldoutData.Bool;
                    UnityEngine.GUI.enabled = true;
                    result = EditorGUILayout.ObjectField(objFieldLabel,
                                                         valInField,
                                                         type,
                                                         allowSceneObject,
                                                         new GUILayoutOption[] { });

                    if (typeof(ScriptAsset).IsAssignableFrom(type))
                    {
                        GUILayout.Space(4);
                        using (new GUI.ColorBlock(Color.Lerp(UnityEngine.GUI.color, Color.green, 0.1f)))
                            createNewAssetButton = GUILayout.Button(GUI.MakeLabel("New", false, "Create new asset"),
                                                                    GUILayout.Width(42),
                                                                    GUILayout.Height(buttonSize));
                    }
                }
                GUILayout.EndHorizontal();

                if (GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition) &&
                    Event.current.type == EventType.MouseDown &&
                    Event.current.button == 0)
                {
                    Event.current.Use();
                    foldoutData.Bool = !foldoutData.Bool;
                    GUIUtility.ExitGUI();
                }

                if (foldoutData.Bool)
                {
                    using (new GUI.Indent(12)) {
                        GUI.Separator();

                        GUILayout.Space(6);

                        AGXUnity.Utils.GUI.WarningLabel("Changes made to this object will affect all objects referencing this asset.",
                                                        skin);

                        GUILayout.Space(6);

                        Editor editor = Editor.CreateEditor(result as Object);
                        if (editor != null)
                        {
                            editor.OnInspectorGUI();
                        }

                        GUI.Separator();
                    }
                }
            }
            else
            {
                result = EditorGUILayout.ObjectField(MakeLabel(wrapper.Member),
                                                     valInField,
                                                     type,
                                                     allowSceneObject,
                                                     new GUILayoutOption[] { });
            }

            if (createNewAssetButton)
            {
                var assetName = type.Name.SplitCamelCase().ToLower();
                var path      = EditorUtility.SaveFilePanel("Create new " + assetName, "Assets", "new " + assetName + ".asset", "asset");
                if (path != string.Empty)
                {
                    var info         = new System.IO.FileInfo(path);
                    var relativePath = IO.Utils.MakeRelative(path, Application.dataPath);
                    var newInstance  = ScriptAsset.Create(type);
                    newInstance.name = info.Name;
                    AssetDatabase.CreateAsset(newInstance, relativePath + (info.Extension == ".asset" ? "" : ".asset"));
                    AssetDatabase.SaveAssets();
                    AssetDatabase.Refresh();

                    result = newInstance;
                }
            }

            return(result);
        }
Example #6
0
        /// <summary>
        /// Trying to generate the objects given the simulation tree.
        /// Throws if something goes wrong.
        /// </summary>
        public void TryGenerate()
        {
            FileInfo.GetOrCreateDataDirectory();

            // Adding one for disabled collisions.
            int numSubProgresses = m_tree.Roots.Length + 1;

            using (var subProgress = m_progressBar.Progress("Generating: " + FileInfo.NameWithExtension, numSubProgresses)) {
                FileInfo.PrefabInstance.transform.position = Vector3.zero;
                FileInfo.PrefabInstance.transform.rotation = Quaternion.identity;
                var fileData = FileInfo.PrefabInstance.GetOrCreateComponent <AGXUnity.IO.RestoredAGXFile>();

                fileData.DataDirectoryId = FileInfo.DataDirectoryId;

                fileData.SolverSettings      = ScriptAsset.Create <SolverSettings>().RestoreLocalDataFrom(Simulation);
                fileData.SolverSettings.name = FindName("SolverSettings_" + FileInfo.Name, "SolverSettings");
                fileData.SolverSettings      = FileInfo.AddOrUpdateExistingAsset(fileData.SolverSettings, AGXUnity.IO.AssetType.Unknown);

                foreach (var root in m_tree.Roots)
                {
                    subProgress.Tick(root.Name == string.Empty ? root.Type.ToString() : root.Name);
                    Generate(root);
                    subProgress.Tack();
                }

                subProgress.Tick("Disabled collisions");
                var disabledCollisionsState = Simulation.getSpace().findDisabledCollisionsState();
                foreach (var namePair in disabledCollisionsState.getDisabledNames())
                {
                    fileData.AddDisabledPair(namePair.first, namePair.second);
                }
                foreach (var idPair in disabledCollisionsState.getDisabledIds())
                {
                    fileData.AddDisabledPair(idPair.first.ToString(), idPair.second.ToString());
                }
                foreach (var geometryPair in disabledCollisionsState.getDisabledGeometyPairs())
                {
                    if (!Tree.IsValid(geometryPair.first) || !Tree.IsValid(geometryPair.second))
                    {
                        continue;
                    }

                    var geometry1Node = m_tree.GetNode(geometryPair.first.getUuid());
                    var geometry2Node = m_tree.GetNode(geometryPair.second.getUuid());
                    if (geometry1Node == null || geometry2Node == null)
                    {
                        Debug.LogWarning("Unreferenced geometry in disabled collisions pair.");
                        continue;
                    }

                    var geometry1Id = geometry2Node.Uuid.str();
                    foreach (var shapeNode in geometry1Node.GetChildren(Node.NodeType.Shape))
                    {
                        shapeNode.GameObject.GetOrCreateComponent <CollisionGroups>().AddGroup(geometry1Id, false);
                    }
                    var geometry2Id = geometry1Node.Uuid.str();
                    foreach (var shapeNode in geometry2Node.GetChildren(Node.NodeType.Shape))
                    {
                        shapeNode.GameObject.GetOrCreateComponent <CollisionGroups>().AddGroup(geometry2Id, false);
                    }

                    fileData.AddDisabledPair(geometry1Id, geometry2Id);
                }
                subProgress.Tack();
            }
        }
Example #7
0
        public static bool HandleType(InvokeWrapper wrapper, T target, GUISkin skin)
        {
            object value      = null;
            bool   isNullable = false;
            Type   type       = wrapper.GetContainingType();

            if (type == typeof(Vector4) && wrapper.CanRead())
            {
                Vector4 valInField = wrapper.Get <Vector4>();
                value = EditorGUILayout.Vector4Field(MakeLabel(wrapper.Member).text, valInField);
            }
            else if (type == typeof(Vector3) && wrapper.CanRead())
            {
                Vector3 valInField = wrapper.Get <Vector3>();
                GUILayout.BeginHorizontal();
                {
                    GUILayout.Label(MakeLabel(wrapper.Member));
                    value = EditorGUILayout.Vector3Field("", valInField);
                }
                GUILayout.EndHorizontal();
            }
            else if (type == typeof(Vector2) && wrapper.CanRead())
            {
                Vector2 valInField = wrapper.Get <Vector2>();
                value = EditorGUILayout.Vector2Field(MakeLabel(wrapper.Member).text, valInField);
            }
            else if ((type == typeof(float) || type == typeof(double)) && wrapper.CanRead())
            {
                float valInField = type == typeof(double) ? Convert.ToSingle(wrapper.Get <double>()) : wrapper.Get <float>();
                FloatSliderInInspector slider = wrapper.GetAttribute <FloatSliderInInspector>();
                if (slider != null)
                {
                    value = EditorGUILayout.Slider(MakeLabel(wrapper.Member), valInField, slider.Min, slider.Max);
                }
                else
                {
                    value = EditorGUILayout.FloatField(MakeLabel(wrapper.Member), valInField, skin.textField);

                    // I can't remember why I tested this approach.
                    //GUILayout.BeginHorizontal();
                    //{
                    //  GUILayout.Label( MakeLabel( wrapper.Member ) );
                    //  value = EditorGUILayout.FloatField( valInField, skin.textField );
                    //}
                    //GUILayout.EndHorizontal();
                }
            }
            else if (type == typeof(int) && wrapper.CanRead())
            {
                int valInField = wrapper.Get <int>();
                value = EditorGUILayout.IntField(MakeLabel(wrapper.Member), valInField, skin.textField);
            }
            else if (type == typeof(bool) && wrapper.CanRead())
            {
                bool valInField = wrapper.Get <bool>();
                value = Utils.GUI.Toggle(MakeLabel(wrapper.Member), valInField, skin.button, skin.label);
            }
            else if (type == typeof(Color) && wrapper.CanRead())
            {
                Color valInField = wrapper.Get <Color>();
                value = EditorGUILayout.ColorField(MakeLabel(wrapper.Member), valInField);
            }
            else if (type == typeof(DefaultAndUserValueFloat) && wrapper.CanRead())
            {
                DefaultAndUserValueFloat valInField = wrapper.Get <DefaultAndUserValueFloat>();

                float newValue = Utils.GUI.HandleDefaultAndUserValue(wrapper.Member.Name, valInField, skin);
                if (wrapper.IsValid(newValue))
                {
                    if (!valInField.UseDefault)
                    {
                        valInField.Value = newValue;
                    }
                    value = valInField;
                }
            }
            else if (type == typeof(DefaultAndUserValueVector3) && wrapper.CanRead())
            {
                DefaultAndUserValueVector3 valInField = wrapper.Get <DefaultAndUserValueVector3>();

                Vector3 newValue = Utils.GUI.HandleDefaultAndUserValue(wrapper.Member.Name, valInField, skin);
                if (wrapper.IsValid(newValue))
                {
                    if (!valInField.UseDefault)
                    {
                        valInField.Value = newValue;
                    }
                    value = valInField;
                }
            }
            else if (type == typeof(RangeReal))
            {
                RangeReal valInField = wrapper.Get <RangeReal>();

                GUILayout.BeginHorizontal();
                {
                    GUILayout.Label(MakeLabel(wrapper.Member), skin.label);
                    valInField.Min = EditorGUILayout.FloatField("", (float)valInField.Min, skin.textField, GUILayout.MaxWidth(64));
                    valInField.Max = EditorGUILayout.FloatField("", (float)valInField.Max, skin.textField, GUILayout.MaxWidth(64));
                }
                GUILayout.EndHorizontal();

                if (valInField.Min > valInField.Max)
                {
                    valInField.Min = valInField.Max;
                }

                value = valInField;
            }
            else if (type == typeof(string) && wrapper.CanRead())
            {
                value = EditorGUILayout.TextField(MakeLabel(wrapper.Member), wrapper.Get <string>(), skin.textField);
            }
            else if (type.IsEnum && type.IsVisible && wrapper.CanRead())
            {
                Enum valInField = wrapper.Get <System.Enum>();
                value = EditorGUILayout.EnumPopup(MakeLabel(wrapper.Member), valInField, skin.button);
            }
            else if (type.IsArray && wrapper.CanRead())
            {
                Array array = wrapper.Get <Array>();
                if (array.Length == 0)
                {
                    GUILayout.BeginHorizontal();
                    {
                        GUILayout.Label(MakeLabel(wrapper.Member), skin.label);
                        GUILayout.Label(Utils.GUI.MakeLabel("Empty array", true), skin.label);
                    }
                    GUILayout.EndHorizontal();
                }
                else
                {
                    Utils.GUI.Separator();
                    using (new Utils.GUI.Indent(12))
                        foreach (object obj in wrapper.Get <Array>())
                        {
                            DrawMembersGUI(obj, target, skin);
                        }
                    Utils.GUI.Separator();
                }
            }
            else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List <>) && wrapper.CanRead())
            {
                HandleList(wrapper, target, skin);
            }
            else if (type == typeof(IFrame) && wrapper.CanRead())
            {
                IFrame frame = wrapper.Get <IFrame>();
                Utils.GUI.HandleFrame(frame, skin);
            }
            else if ((typeof(ScriptAsset).IsAssignableFrom(type) ||
                      type.BaseType == typeof(UnityEngine.Object) ||
                      type.BaseType == typeof(ScriptComponent)) && wrapper.CanRead())
            {
                bool allowSceneObject = type == typeof(GameObject) ||
                                        type.BaseType == typeof(ScriptComponent);
                UnityEngine.Object valInField = wrapper.Get <UnityEngine.Object>();
                bool recursiveEditing         = wrapper.HasAttribute <AllowRecursiveEditing>();
                bool createNewAssetButton     = false;

                if (recursiveEditing)
                {
                    var foldoutData = EditorData.Instance.GetData(target as UnityEngine.Object, wrapper.Member.Name);

                    GUILayout.BeginHorizontal();
                    {
                        var objFieldLabel = MakeLabel(wrapper.Member);
                        var buttonSize    = skin.label.CalcHeight(objFieldLabel, Screen.width);
                        UnityEngine.GUI.enabled = valInField != null;
                        foldoutData.Bool        = GUILayout.Button(Utils.GUI.MakeLabel(foldoutData.Bool ? "-" : "+"),
                                                                   skin.button,
                                                                   new GUILayoutOption[] { GUILayout.Width(20.0f), GUILayout.Height(buttonSize) }) ?
                                                  // Button clicked - toggle current value.
                                                  !foldoutData.Bool :
                                                  // If foldout were enabled but valInField has changed to null - foldout will become disabled.
                                                  valInField != null && foldoutData.Bool;
                        UnityEngine.GUI.enabled = true;
                        value = EditorGUILayout.ObjectField(objFieldLabel, valInField, type, allowSceneObject, new GUILayoutOption[] { });

                        if (typeof(ScriptAsset).IsAssignableFrom(type))
                        {
                            GUILayout.Space(4);
                            using (new GUI.ColorBlock(Color.Lerp(UnityEngine.GUI.color, Color.green, 0.1f)))
                                createNewAssetButton = GUILayout.Button(GUI.MakeLabel("New", false, "Create new asset"),
                                                                        GUILayout.Width(42),
                                                                        GUILayout.Height(buttonSize));
                        }
                    }
                    GUILayout.EndHorizontal();

                    if (GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition) && Event.current.type == EventType.MouseDown && Event.current.button == 0)
                    {
                        foldoutData.Bool = !foldoutData.Bool;
                        GUIUtility.ExitGUI();
                    }

                    if (foldoutData.Bool)
                    {
                        using (new Utils.GUI.Indent(12)) {
                            Utils.GUI.Separator();

                            GUILayout.Space(6);

                            GUILayout.Label(Utils.GUI.MakeLabel("Changes made to this object will affect all objects referencing this asset.",
                                                                Color.Lerp(Color.red, Color.white, 0.25f),
                                                                true),
                                            new GUIStyle(skin.textArea)
                            {
                                alignment = TextAnchor.MiddleCenter
                            });

                            GUILayout.Space(6);

                            // Executes OnInspectorGUI on a custom editor if it exist - otherwise Update.
                            Editor editor = null;
                            if (value is UnityEngine.Object && (editor = Editor.CreateEditor(value as UnityEngine.Object)) != null)
                            {
                                var updateMethod = typeof(BaseEditor <>).MakeGenericType(value.GetType()).GetMethod("OnRecursiveInspectorGUI", BindingFlags.Public | BindingFlags.Instance);
                                updateMethod.Invoke(editor, new object[] { target });
                            }
                            else
                            {
                                var updateMethod = typeof(BaseEditor <>).MakeGenericType(typeof(T)).GetMethod("Update", BindingFlags.Public | BindingFlags.Static);
                                updateMethod.Invoke(null, new object[] { value, target, skin });
                            }

                            Utils.GUI.Separator();
                        }
                    }
                }
                else
                {
                    value = EditorGUILayout.ObjectField(MakeLabel(wrapper.Member), valInField, type, allowSceneObject, new GUILayoutOption[] { });
                }

                if (createNewAssetButton)
                {
                    var assetName = type.Name.SplitCamelCase().ToLower();
                    var result    = EditorUtility.SaveFilePanel("Create new " + assetName, "Assets", "new " + assetName + ".asset", "asset");
                    if (result != string.Empty)
                    {
                        var info         = new System.IO.FileInfo(result);
                        var relativePath = IO.Utils.MakeRelative(result, Application.dataPath);
                        var newInstance  = ScriptAsset.Create(type);
                        newInstance.name = info.Name;
                        AssetDatabase.CreateAsset(newInstance, relativePath + (info.Extension == ".asset" ? "" : ".asset"));
                        AssetDatabase.SaveAssets();
                        AssetDatabase.Refresh();

                        value = newInstance;
                    }
                }

                isNullable = true;
            }
            else if (type.IsClass && wrapper.CanRead())
            {
            }

            return(UnityEngine.GUI.changed &&
                   (value != null || isNullable) &&
                   wrapper.ConditionalSet(value));
        }