Drunk3n_P1nky

I have a plain serialized C# class which has fields: SkeletonDataAsset and string with [SpineAnimation] attribute.
Also, I have a GameObject on my scene with monobehaviour script which has a list of non-monobehaviour instances of my class. What I've noticed that [SpineAnimation] attribute works perfectly with Monobehaviours and ScriptableObjects showing dropdown menu with all animations. But with plain C# script I only have an error or string field (with fallbackToTextField being true) to fill in. Is it even possible to display this menu of animations in such case?
Thank you for your attention in advance!
Drunk3n_P1nky
  • Posts: 5

Harald

The SpineAnimation attribute has some parameters, such as the target SkeletonDataAsset. If you don't specify any of these parameters, leaving them at the default will lead to automatic assignment, which likely fails in your case. So the solution should be to specify the dataField parameter, as in [SpineAnimation(dataField: "skeletonDataAsset")], which then uses the attribute named skeletonDataAsset of the same class.

A better example of the dataField in use would be SpineboyTargetController.cs line L37, where the target is not on the same GameObject:
[SpineBone(dataField: "skeletonAnimation")]
User avatar
Harald

Harri
  • Posts: 4164

Drunk3n_P1nky

Thank you very much for your reply! I surely use dataField and fill the name of my skeletonDataAsset field in. But I still recieve an error. I believe it has something to do with my customly serialized C# classes. For instance, I wrote a code to serialize C# queue to see it in inspector. It looks like this:
[System.Serializable]
public class UnitySerializedQueue : Queue<DialogueNode>, ISerializationCallbackReceiver
{
[SerializeField, HideInInspector]
private List<DialogueNode> _dialogueLines = new List<DialogueNode>();

public void OnAfterDeserialize()
{
Clear();
foreach (var item in _dialogueLines)
{
Enqueue(item);
}
}

public void OnBeforeSerialize()
{
_dialogueLines.Clear();

foreach (var item in this)
{
_dialogueLines.Add(item);
}
}
And the script where I have skeletonDataAsset Reference and animation field:
public class DialogueNode : IEmotion, IHasSkeletonDataAsset
{
public Speaker Speaker => _speaker;
public SkeletonDataAsset SkeletonDataAsset
{
get
{
return _skeletonDataAsset;
}
set
{
_skeletonDataAsset = value;
}
}
public List<GameObject> Bubbles => _bubbles;
public string Animation => _animation;
public bool Loop => _loop;
public AudioSource AudioSource => _audioSource;
public float LifeTime => _lifeTime;
public float WaitTime => _waitTime;
public int Chance => _chance;
[PropertyOrder(1)]
public UnityEvent Outcome;

[SerializeField]
private Speaker _speaker;
[SerializeField]
private SkeletonDataAsset _skeletonDataAsset;
[SerializeField]
private List<GameObject> _bubbles;
[SerializeField, SpineAnimation(dataField = "_skeletonDataAsset")]
private string _animation;
[SerializeField]
private bool _loop;
[SerializeField]
private AudioSource _audioSource;
[SerializeField]
private float _lifeTime, _waitTime;
[SerializeField]
private int _chance;
}
I guess it doesn't go that deep. Do you have any hints for me? Thanks once again!
Drunk3n_P1nky
  • Posts: 5

Harald

Why do you have HideInInspector set as attribute of your private List<DialogueNode> _dialogueLines? I wonder why it displays the list of DialogueNode at all.
User avatar
Harald

Harri
  • Posts: 4164

Drunk3n_P1nky

Harald wrote:Why do you have HideInInspector set as attribute of your private List<DialogueNode> _dialogueLines?
Result would be the same. I don't think HideInInspector works with classes that don't derive from monobehaviour. I've got rid of this attribute, but result is the same. It's displayed in inspector. Reference to SkeletonDataAsset still not found :(
Drunk3n_P1nky
  • Posts: 5

Harald

Sorry to hear that. Did you try setting a debug breakpoint in SpineAttributeDrawers.cs at SpineTreeItemDrawerBase in the method OnGUI, at the following line:
SerializedProperty dataField = property.FindBaseOrSiblingProperty(TargetAttribute.dataField);

I suspect that the sibling property already fails to be resolved, but it would be better to check that to be sure.
User avatar
Harald

Harri
  • Posts: 4164

Drunk3n_P1nky

Harald wrote: Did you try setting a debug breakpoint
I did. I tried to compare my queue case and regular monobehaviour withDialogueNode field. In the first case property path is always just _skeletonDataAsset. Like it's already inside class or something like that. Which is definitely irregular. In the second case I get nameOfDialogueNodeField._skeletonDataAsset. Can I somehow set certain path manually? But I guess it anyway won't work out for me :(
Drunk3n_P1nky
  • Posts: 5

Harald

You could try [SpineBone(dataField: "nameOfDialogueNodeField._skeletonDataAsset")] in your non-MonoBehaviour class, just for testing if that basically works. In general such paths to second-level member variables of the form a.b should work when normally resolving properties in custom inspector code.
User avatar
Harald

Harri
  • Posts: 4164

Drunk3n_P1nky

I believe it's impossible to give valid path for something that is inside queue or dictionary. But it works with Lists. I guess I'm about to debug it usage with lists and see how it acts. Maybe it will force me to find some solution. But for now I have no clue
Drunk3n_P1nky
  • Posts: 5

Harald

Sorry for the late reply. I just tried a simplified version of your code posted earlier, only using List<> and nothing queue-related added, and it works without any issues:
using Spine.Unity;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class DialogueNode {

[SerializeField]
private SkeletonDataAsset _skeletonDataAsset;

[SerializeField, SpineAnimation(dataField = "_skeletonDataAsset")]
private string _animation;
}

public class TestStructAnimationProperty : MonoBehaviour {
public DialogueNode dialogueLine = new DialogueNode();
public List<DialogueNode> dialogueLines = new List<DialogueNode>();
}
User avatar
Harald

Harri
  • Posts: 4164


Return to Unity