Compare commits

...

5 Commits

Author SHA1 Message Date
max
310c45cb98 Update package 2022-05-07 01:39:35 +02:00
max
087a0f7fdb Update ExtendedScriptableObjectDrawer.cs 2022-05-07 01:33:01 +02:00
max
f00c7d43aa NonSerialized fields
Fixed private fields in ScriptableObject getting serialized.
2022-01-02 17:11:40 +01:00
max
22fee290ce Instance indicator colors
Added instance colors to better indicate what is being displayed.
Code refactor.
2021-12-24 03:19:19 +01:00
max
91648de3d9 ExpandableScriptableObjectDrawer 2021-12-23 04:02:01 +01:00
16 changed files with 429 additions and 21 deletions

View File

@ -1,5 +1,12 @@
# Change Log:
## 1.1.3
- Update ExtendedScriptableObjectDrawer.
## 1.1.2
- Fixed private fields in ScriptableObject getting serialized.
## 1.1.1
- Instance indicator colors.
- Code refactor.
## 1.1.0
- ExstendableScriptableObjectDrawer.
## 1.0.0
- Base project.
- Base project.

8
Editor.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d458e753979e51e45b177e41f406d936
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Editor/Drawers.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d838f79c4b7c4b94080dbdb3d4d7c434
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,155 @@
// References:
// https://gist.github.com/tomkail/ba4136e6aa990f4dc94e0d39ec6a058c
// Developed by Tom Kail at Inkle
// Released under the MIT Licence as held at https://opensource.org/licenses/MIT
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace ScriptableData.Editor
{
[CustomPropertyDrawer(typeof(ScriptableObject), true)]
public class ExtendedScriptableObjectDrawer : PropertyDrawer
{
// Permamently exclude classes from being affected by the drawer.
private static readonly string[] ignoredFullClassNames = new string[] { "TMPro.TMP_FontAsset" };
private static readonly GUIContent buttonContent = EditorGUIUtility.IconContent("d_ScriptableObject On Icon");
private const int buttonWidth = 16;
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
float totalHeight = EditorGUIUtility.singleLineHeight;
SerializedObject serializedObject = null;
if (property.objectReferenceValue is ScriptableObject scriptableObject)
{
serializedObject = new SerializedObject(scriptableObject);
}
if (serializedObject == null || !serializedObject.HasVisableSubProperties() || fieldInfo.HasAttribute<NonExtendableAttribute>())
{
return totalHeight;
}
if (property.isExpanded)
{
// Iterate over all the values and draw them.
SerializedProperty p = serializedObject.GetIterator();
if (p.NextVisible(true))
{
do
{
// Skip drawing the class file.
if (EditorUtils.IsIgnoredProperty(p))
{
continue;
}
float height = EditorGUI.GetPropertyHeight(p, null, true) + EditorGUIUtility.standardVerticalSpacing;
totalHeight += height;
}
while (p.NextVisible(false));
}
// Add a tiny bit of height if open for the background
totalHeight += EditorGUIUtility.standardVerticalSpacing;
}
return totalHeight;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
Type fieldType = EditorUtils.GetFieldType(fieldInfo);
// Draw with default drawer.
if (fieldType == null || HasIgnoredClassName(fieldType) || fieldInfo.HasAttribute<NonExtendableAttribute>())
{
EditorGUI.PropertyField(position, property, label);
EditorGUI.EndProperty();
return;
}
Rect foldoutRect = new Rect(position.x, position.y, EditorGUIUtility.labelWidth, EditorGUIUtility.singleLineHeight);
Rect indentedPosition = EditorGUI.IndentedRect(position);
float indentOffset = indentedPosition.x - position.x;
Rect propertyRect = new Rect(position.x + (EditorGUIUtility.labelWidth - indentOffset + 2), position.y, position.width - (EditorGUIUtility.labelWidth - indentOffset + 2), EditorGUIUtility.singleLineHeight);
SerializedObject serializedObject = null;
if(property.objectReferenceValue is ScriptableObject scriptableObject)
{
serializedObject = new SerializedObject(scriptableObject);
}
// Check for sub properties and if the property can be expanded.
if (serializedObject != null && serializedObject.HasVisableSubProperties())
{
property.isExpanded = EditorGUI.Foldout(foldoutRect, property.isExpanded, new GUIContent(property.displayName), true);
if (property.isExpanded)
{
// Draw sub properties.
serializedObject.Draw(position);
}
}
else
{
EditorGUI.LabelField(foldoutRect, new GUIContent(property.displayName));
if (property.objectReferenceValue == null)
{
propertyRect.width -= buttonWidth;
// Draw create button.
Rect buttonRect = new Rect(position.x + position.width - buttonWidth, position.y + 1, buttonWidth, EditorGUIUtility.singleLineHeight);
DrawScriptableObjectCreateButton(buttonRect, property, fieldType);
}
}
EditorGUI.BeginChangeCheck();
// Draw object field.
EditorGUI.PropertyField(propertyRect, property, GUIContent.none, false);
if (EditorGUI.EndChangeCheck())
{
property.serializedObject.ApplyModifiedProperties();
}
property.serializedObject.ApplyModifiedProperties();
EditorGUI.EndProperty();
}
private static void DrawScriptableObjectCreateButton(Rect position, SerializedProperty property, Type type)
{
if (GUI.Button(position, buttonContent, EditorStyles.iconButton))
{
GenericMenu typeChooser = new GenericMenu();
IEnumerable<Type> types = type.Assembly.GetTypes().Where(t => type.IsAssignableFrom(t));
foreach (Type t in types)
{
if (t.IsAbstract)
{
continue;
}
typeChooser.AddItem(new GUIContent(t.Name), false, (o) => {
property.objectReferenceValue = EditorUtils.CreateAssetWithSavePrompt(o as Type, EditorUtils.GetSelectedAssetPath(property));
property.serializedObject.ApplyModifiedProperties();
}, t);
}
typeChooser.ShowAsContext();
}
}
private static bool HasIgnoredClassName(Type type)
{
return ignoredFullClassNames.Contains(type.FullName);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c9558a1cbd654b5499f5394666f2479d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

151
Editor/EditorUtils.cs Normal file
View File

@ -0,0 +1,151 @@
using System;
using System.Reflection;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using Random = UnityEngine.Random;
namespace ScriptableData.Editor
{
public static class EditorUtils
{
public static string GetSelectedAssetPath(SerializedProperty property)
{
string selectedAssetPath = "Assets";
if (property.serializedObject.targetObject is MonoBehaviour behaviour)
{
MonoScript ms = MonoScript.FromMonoBehaviour(behaviour);
selectedAssetPath = System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(ms));
}
return selectedAssetPath;
}
public static ScriptableObject CreateAssetWithSavePrompt(Type type, string path)
{
path = EditorUtility.SaveFilePanelInProject("Save ScriptableObject", type.Name + ".asset", "asset", "Enter a file name for the ScriptableObject.", path);
if (string.IsNullOrWhiteSpace(path)) {
return null;
}
ScriptableObject asset = ScriptableObject.CreateInstance(type);
AssetDatabase.CreateAsset(asset, path);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
EditorGUIUtility.PingObject(asset);
return asset;
}
public static bool HasAttribute<T>(this FieldInfo fieldInfo)
{
Attribute[] attributes = Attribute.GetCustomAttributes(fieldInfo);
foreach (Attribute a in attributes)
{
if (a is T)
{
return true;
}
}
return false;
}
public static Type GetFieldType(FieldInfo fieldInfo)
{
Type type = fieldInfo.FieldType;
if (type.IsArray)
{
type = type.GetElementType();
}
else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
{
type = type.GetGenericArguments()[0];
}
return type;
}
public static void Draw(this SerializedObject serializedObject, Rect position)
{
// Get position with indentation.
Rect indentedPosition = EditorGUI.IndentedRect(position);
EditorGUI.indentLevel++;
// Draw a background that shows us clearly which fields are part of the ScriptableObject.
GUI.Box(new Rect(indentedPosition.x, position.y + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing - 1, position.width, position.height - EditorGUIUtility.singleLineHeight - EditorGUIUtility.standardVerticalSpacing), "");
// Draw color coded side to indicate the scriptable object instance.
if (serializedObject.targetObject != null)
{
Random.InitState(serializedObject.targetObject.GetInstanceID());
EditorGUI.DrawRect(new Rect(indentedPosition.x - EditorGUIUtility.standardVerticalSpacing, position.y + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing - 1, EditorGUIUtility.standardVerticalSpacing, position.height - EditorGUIUtility.singleLineHeight - EditorGUIUtility.standardVerticalSpacing), Random.ColorHSV(0f, 1f, 1f, 1f, 0.75f, 0.75f));
}
Rect pRect = new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing, position.width, 0);
// Iterate over all the values and draw them.
SerializedProperty p = serializedObject.GetIterator();
EditorGUI.BeginChangeCheck();
if (p.NextVisible(true))
{
do
{
if (IsIgnoredProperty(p))
{
continue;
}
pRect.height = EditorGUI.GetPropertyHeight(p, new GUIContent(p.displayName), true);
// Draw property.
EditorGUI.PropertyField(pRect, p, true);
pRect.y += pRect.height + EditorGUIUtility.standardVerticalSpacing;
}
while (p.NextVisible(false));
}
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
}
EditorGUI.indentLevel--;
}
public static bool HasVisableSubProperties(this SerializedObject serializedObject)
{
SerializedProperty p = serializedObject.GetIterator();
if (p.NextVisible(true))
{
do
{
if (IsIgnoredProperty(p))
{
continue;
}
return true;
}
while (p.NextVisible(false));
}
return false;
}
public static bool IsIgnoredProperty(SerializedProperty property)
{
// Skip drawing the class file.
if (property.name == "m_Script")
{
return true;
}
return false;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a7cb0a51d6707b42a7d94c7ad8f42dc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,18 @@
{
"name": "VertexColor.ScriptableData.Editor",
"rootNamespace": "ScriptableData.Editor",
"references": [
"GUID:bd2fa452e376b7e4e8356eed741e5eea"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 67726662be89db44e8fafa5427d4ed5f
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -33,6 +33,13 @@ public class ScriptableEvent<T0, T1, T2, T3> : ScriptableObject {}
[CreateAssetMenu(menuName = "ScriptableData/Event/Vector3", order = 147)]
public class SEVector3 : ScriptableEvent<Vector3> {}
```
## ExtendedScriptableObjectDrawer
If you don't want to use the extended drawer, use the `[NonExpandable]` attribute.
### Example:
```C#
[NonExpandable]
public SEVector3 myVector3;
```
## Install
[Installing from a Git URL](https://docs.unity3d.com/Manual/upm-ui-giturl.html)

8
Runtime/Attributes.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 53eb228a806717b42ad447e290770d87
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
using System;
using UnityEngine;
namespace ScriptableData
{
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true, Inherited = true)]
public class NonExtendableAttribute : PropertyAttribute { }
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f456f876476c1a54b86a231e0271cf82
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -7,7 +7,7 @@ namespace ScriptableData
{
public event Action<T0> OnValueChangedEvent;
private T0 _value;
[NonSerialized] private T0 _value;
public T0 Value
{
get
@ -37,7 +37,7 @@ namespace ScriptableData
{
public event Action<T0, T1> OnValueChangedEvent;
private T0 _value;
[NonSerialized] private T0 _value;
public T0 Value
{
get
@ -51,7 +51,7 @@ namespace ScriptableData
}
}
private T1 _value1;
[NonSerialized] private T1 _value1;
public T1 Value1
{
get
@ -88,7 +88,7 @@ namespace ScriptableData
{
public event Action<T0, T1, T2> OnValueChangedEvent;
private T0 _value;
[NonSerialized] private T0 _value;
public T0 Value
{
get
@ -102,7 +102,7 @@ namespace ScriptableData
}
}
private T1 _value1;
[NonSerialized] private T1 _value1;
public T1 Value1
{
get
@ -116,7 +116,7 @@ namespace ScriptableData
}
}
private T2 _value2;
[NonSerialized] private T2 _value2;
public T2 Value2
{
get
@ -161,7 +161,7 @@ namespace ScriptableData
{
public event Action<T0, T1, T2, T3> OnValueChangedEvent;
private T0 _value;
[NonSerialized] private T0 _value;
public T0 Value
{
get
@ -175,7 +175,7 @@ namespace ScriptableData
}
}
private T1 _value1;
[NonSerialized] private T1 _value1;
public T1 Value1
{
get
@ -189,7 +189,7 @@ namespace ScriptableData
}
}
private T2 _value2;
[NonSerialized] private T2 _value2;
public T2 Value2
{
get
@ -203,7 +203,7 @@ namespace ScriptableData
}
}
private T3 _value3;
[NonSerialized] private T3 _value3;
public T3 Value3
{
get

View File

@ -1,11 +1,9 @@
This package borrows code from various different sources, including:
# []()
### Relevant Files
- []()
## ExtendedScriptableObjectDrawer
- [x] Modified
### Credits
- Author: []()
- Source: []()
- License: []()
- Author: Tom Kail
- Source: [ExtendedScriptableObjectDrawer](https://gist.github.com/tomkail/ba4136e6aa990f4dc94e0d39ec6a058c)
- License: [MIT](https://opensource.org/licenses/MIT)

View File

@ -1,7 +1,7 @@
{
"name": "com.vertexcolor.scriptabledata",
"displayName": "ScriptableData",
"version": "1.0.0",
"version": "1.1.3",
"unity": "2019.1",
"description": "ScriptableData code base for ScriptableObject workflow.",
"category": "Tool",