@yuzuvalentine - to give you an idea of the limitation and as to why youâre limited to the âhost objectâ spiney referenced is to look at the yaml associated with a serializereference.
Iâm going to use a ScriptableObject here just because the yaml for those is much simpler than prefabs or scenes. But the principles still stand between them all.
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1af0673dba5990a478290442f951312e, type: 3}
m_Name: NotNPC-Mask
m_EditorClassIdentifier:
_mode:
rid: 5484116880779116551
references:
version: 2
RefIds:
- rid: 5484116880779116551
type: {class: EventActivatorMask/Inverted, ns: com.spacepuppy, asm: com.spacepuppy}
data:
mode:
rid: 5484116880779116552
- rid: 5484116880779116552
type: {class: EntityActivatorMask/ByEntityType, ns: com.wreckage, asm: Assembly-CSharp}
data:
type: 4
This is for this ScriptableObject which is an EventActivatorMask from my last post:

Note that it consists of 2 'IModeâs in this case. Inverted and ByEntityType.
Our yaml basically goes:
some identification stuff for yaml version
line header for a coming object
object declaration (MonoBehaviour: ⌠I know this is a ScriptableObject, but Unity for whatever reason just uses the same identifier for both SO and MB)
required fields by assets internally (ids, hideflags, etc)
m_Script - this actually is what tells unity which class your asset is, not that itâs defined via guid. If you look at the meta file for EventActivatorMask in my proj itâll have the guid â1af0673dba5990a478290442f951312eâ in it
m_Name - the name
m_EditorClassIdentifier - this is just some editor time only junk
âŚ
Now we get to the meat of our object. This is where our custom stuff is.
It starts by declaring the name of our property to be set, in this case _mode. From my previous post thatâs the 1 field/variable in my EventActivatorMask.
And that _mode is set to a specific thing:
rid: 5484116880779116551
After this youâll find the âreferences:â, this is where our referenced objects are declared and theyâre done on a per object basis. If this was a prefab youâd see all the âreferences:â stuff then another ââ !u!114 âŚâ bit moving onto the next MonoBehaviour or other script after that.
So following this âreferences:â we see a version number and entries for 2 references assigned these weird large numbers. Those numbers are just identifiers.
But weâll see the first one has that same 5484116880779116551. This is how the serialization engine knows which of the 2 objects gets put in _mode back above.
This first object has info about what is the type of the object. Note how this is by name and not by guid. This is actually an important consideration⌠you can relatively easily rename your MonoBehaviours and ScriptableObjects and your serialized assets will update respectively because as long as that meta file exists named the same thing with the guid in it, thatâs how Unity looks those up. But NOT for SerializeReference! This is actually by name⌠if you change the name of the class or move its namespace it will break the serialized object. Thereâs a way to deal with this using the âMovedFromâ attribute, but ainât going to lie it has some quarks to it depending on your version of unity, you can google about this subject and find threads discussing it.
But yeah, after that is a data which is the fields of this type, and note this first one has a rid: to the next. Thatâs because our âInvertedâ mode has a nested SerializeReference:
[System.Serializable]
public class Inverted : IMode
{
[SerializeReference, SerializeRefPicker(typeof(IMode), AlwaysExpanded = true)]
public IMode mode;
public bool Intersects(Object obj) => mode != null ? !mode.Intersects(obj) : true;
}
And that rid: has the number for the next object in our list of reference objects and it is configured with the value â4â in its type field. (4 in this case is the enum value for NPC from my pic above)
âŚ
But yeah. You should now see why you canât just drag and drop something into the editor (honestly Iâm with @CodeSmile when he asked what you were expecting to drag in regards to MyClass).
Honestly at the end of the day⌠itâs like weâre serializing really simplistic pointers. You know, like in C, where a pointer is really just an int that is the address of some struct. That rid: ###### is really like the address of some variable like if you said &myval in C. And our fields are just MyValType* refs to it.
The 2 main benefits of this are:
-
polymorphic serialization so that while the field is of type IAbstractType, it can serialize the distinct fields of the ConcreteType
-
you can have recursive links to objects like in a link list
What do I mean by that 2nd thing? Well⌠if you just do this:
class MyScript : ScriptableObject
{
public MyData root;
[System.Serializable]
public class MyData
{
public int value;
public MyData next;
}
}
Unity would freak out! Reason being that unityâs normal serialization ALWAYS fills in a serialized type (it never assigns null). So the serializer will fill in ârootâ which consists of an int and a MyData. So it then fills in ânextâ with a MyData which consists of an int and a MyData. So it fills in the next ânextâ with a MyData which consists of an int and a MyData. So it fills in the next next ânextâ with a MyData which consists of an⌠ad infinitum.
The yaml would effectively look like:
root:
value: 0
next:
value: 0
next:
value: 0
next:
value: 0
... crash
By giving them these âridâ integers it can now just shove the rid into ârootâ or ânextâ, or 0 (I think) for null. And if there are N distinct objects regardless of the linked list layout, it just has the N and references them accordingly.
âŚ
So yeah, itâs a really simplistic system. Nothing crazy going on here. And as a result its usefulness is limited to something less than what youâre hoping for unfortunately.