Author Topic: Editor serialization - collection of interface type?  (Read 3018 times)

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Editor serialization - collection of interface type?
« on: December 19, 2016, 07:39:59 PM »
Firstly, this isn't related to TNet, but since TNet has incredible serialization I figured it wouldn't hurt to post it here.

I have a UIContainer with a public List<IDisplayable> ObservedData field.
Unity Editor doesn't serialize interfaces, so this field doesn't show up on the Inspector.
I'd like to fix this. I'm currently using a custom inspector. Accepting a GameObject as input, I then use reflection to iterate over all MonoBehaviour's and their fields (and the fields fields) to build a List<string> of typenames and fieldnames which I can then display in a popup.
The MonoBehaviour, string typeName, and string fieldName are stored on the UIContainer. In Start() I use reflection to (finally) grab the reference.

This is horrible and I hate it. Is there a better way of doing this? The ObservedData on the UIContainer won't ever be modified; it's only ever read. Additionally, I'd like to support assigning references that aren't implicitly List<IDisplayable> but can be cast without resulting in a new instance. For example, setting UIInventoryContainer's ObservedData to PlayerInventory.Items (which is List<IPickupable> [IPickupable derives from IDisplayable]), any changes made to PlayerInventory.Items will be reflected in ObservedData.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Editor serialization - collection of interface type?
« Reply #1 on: December 19, 2016, 11:16:52 PM »
Obvious question is, why are you doing this? You only need this data in the editor, since you're only trying to visualize your data in inspector. Just create an editor class for your UIContainer, and in OnInspectorGUI cast 'target' into UIContainer, and go through its data, visualizing it as you see fit. NGUI does this everywhere, as it's older code -- before SerializedProperty was added.

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Editor serialization - collection of interface type?
« Reply #2 on: December 20, 2016, 05:24:30 AM »
I'm not trying to visualize the data, I'm trying to set the data. Like how if you have a public GameObject field1 on a component, the Inspector allows you to drag a GameObject from the scene hierarchy into the slot on the component's Inspector. Then at runtime field1 points to the GameObject that you dragged onto it. I'm trying to replicate this except with an interface instead of a GameObject.
The field isn't even shown as a SerializedProperty, frustratingly, otherwise I'd be using that :P

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Editor serialization - collection of interface type?
« Reply #3 on: December 20, 2016, 01:47:10 PM »
If you can visualize it, you can set it. And I'm not saying you should use SerializedProperty. I'm saying you should create your own editor class and display whatever you want, including making it settable via inspector.

Inspector is fully scriptable. You can display a hairy donkey there if you want.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Editor serialization - collection of interface type?
« Reply #4 on: December 20, 2016, 01:50:24 PM »
Here's an example for you:
  1. using UnityEngine;
  2. using UnityEditor;
  3.  
  4. [CanEditMultipleObjects]
  5. [CustomEditor(typeof(FactionEntity), true)]
  6. public class FactionEntityEditor : Editor
  7. {
  8.         public override void OnInspectorGUI ()
  9.         {
  10.                 serializedObject.Update();
  11.  
  12.                 var obj = target as FactionEntity;
  13.  
  14.                 if (Application.isPlaying && obj.tno != null && obj.tno.isActiveAndEnabled && obj.tno.uid != 0)
  15.                 {
  16.                         EditorGUI.BeginDisabledGroup(true);
  17.                         EditorGUILayout.LabelField("Faction", obj.factionName);
  18.                         EditorGUILayout.FloatField("Temperature", obj.externalTemperature - 273.15f);
  19.  
  20.                         var currentTile = ProceduralTerrain.GetTile(obj.tno.channelID);
  21.                         var hoverTile = ProceduralTerrain.GetTile(obj.trans.position);
  22.  
  23.                         EditorGUILayout.LabelField("Current Tile", (currentTile != null ? currentTile.ix + " " + currentTile.iz : "null"));
  24.                         EditorGUILayout.LabelField("Hover Tile", (hoverTile != null ? hoverTile.ix + " " + hoverTile.iz : "null"));
  25.                         EditorGUI.EndDisabledGroup();
  26.                 }
  27.  
  28.                 DrawCustomProperties();
  29.                
  30.                 serializedObject.ApplyModifiedProperties();
  31.         }
  32.  
  33.         protected virtual void DrawCustomProperties ()
  34.         {
  35.                 GUILayout.Space(6f);
  36.                 base.DrawDefaultInspector();
  37.         }
  38. }
  39.  
In addition to properties, I show a bunch of data -- faction, temperature, current terrain tile. To make something settable, I would use EditorGUILayout.TextField instead of LabelField, or any other function that returns some value -- EditorGUILayout.IntField, Toggle, MinMaxSlider, etc.

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Editor serialization - collection of interface type?
« Reply #5 on: December 20, 2016, 07:36:31 PM »
I'd like to be able to do this at edit-time (not while Application.isPlaying). Target isn't an instance reference at that point. I suppose it can't be done without wrapping or adding an additional byte[] to each class to hold serialized data. Maybe Unity will have better support for interfaces in the future.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Editor serialization - collection of interface type?
« Reply #6 on: December 24, 2016, 11:28:06 PM »
Application.isPlaying check is there because the data I am trying to display doesn't exist at edit time. It was just an example.