I have a script called HandSkeleton
for which I wrote a custom editor. HandSkeleton
has a field of type HandSkeletonData
which is a ScriptableObject
. I wrote a custome inspector which can save some values from HandSkeleton
to the HandSkeletonData
it's referencing.
Here is the code:
[CustomEditor(typeof(HandSkeleton))]
public class HandSkeletonEditor : UnityEditor.Editor
{
private const string BasePath = "Assets/ScriptableObjects/HandSkeletonData";
public override void OnInspectorGUI()
{
DrawDefaultInspector();
var handSkeleton = (HandSkeleton)target;
if (GUILayout.Button("Save hand skeleton data"))
{
var handSkeletonTransform = handSkeleton.transform;
var rootName = handSkeletonTransform.root.name;
var parentName = handSkeletonTransform.parent.name;
var skeletonName = handSkeletonTransform.name;
if (handSkeleton.handSkeletonData == null)
{
var so = CreateInstance<HandSkeletonData>();
if (!AssetDatabase.IsValidFolder(BasePath + $"/{rootName}"))
AssetDatabase.CreateFolder(BasePath, rootName);
AssetDatabase.CreateAsset(so, $"{BasePath}/{rootName}/{parentName}_{skeletonName}.asset");
serializedObject.FindProperty(nameof(handSkeleton.handSkeletonData))
.objectReferenceValue = so;
serializedObject.ApplyModifiedProperties();
}
var rotations = handSkeleton.EditorInitialized.GetAllFingerSegmentRotations()
.Select(x => (Quaternion[])x.Clone())
.ToArray();
// here I change the Scriptable Object
handSkeleton.handSkeletonData.FingerSegmentRotations = rotations;
EditorUtility.SetDirty(handSkeleton.handSkeletonData);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
}
The issue is that the changes made to handSkeletonData
are lost after I refresh the editor. I found many other posts where people had the same issue but it was mostly caused by not calling EditorUtility.SetDirty()
. Am I calling it wrong? Or is there something else I'm doing wrong?
Turns out the issue wasn't the way I was saving the Scriptable Object
, but rather what was saved inside it - a 2D array of Quaternions
. Unity simply doesn't serialize 2D arrays. To fix this I changed the 2D array to a 1D array and am accessing it through a property. If anyone is interested here is the code for this:
[HideInInspector] [SerializeField] private Quaternion[] fingerSegmentRotations;
public Quaternion[][] FingerSegmentRotations
{
get
{
if (fingerSegmentRotations == null || fingerSegmentRotations.Length == 0) return null;
var rotations = new Quaternion[HandSkeleton.FingerCount][];
for (var i = 0; i < HandSkeleton.FingerCount; i++)
{
rotations[i] = new Quaternion[HandSkeleton.SegmentCount];
for (var j = 0; j < HandSkeleton.SegmentCount; j++)
rotations[i][j] = fingerSegmentRotations[i * HandSkeleton.SegmentCount + j];
}
return rotations;
}
set
{
fingerSegmentRotations = new Quaternion[HandSkeleton.FingerCount * HandSkeleton.SegmentCount];
for (var i = 0; i < HandSkeleton.FingerCount; i++)
for (var j = 0; j < HandSkeleton.SegmentCount; j++)
fingerSegmentRotations[i * HandSkeleton.SegmentCount + j] = value[i][j];
}
}