Search Unity

How do I make member structs accessible in the editor?

Discussion in 'Editor & General Support' started by Jim Offerman, Dec 7, 2009.

  1. Jim Offerman

    Jim Offerman

    Joined:
    Jul 17, 2009
    Posts:
    177
    Suppose I have a class Foo and some member data that I wish to encapsulate in a struct Bar, like so:

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Foo : MonoBehaviour
    5. {  
    6.     public struct Bar { public int a; public float b; }
    7.     public Bar m_bar;
    8. }
    Is there a way for me to make the members of m_bar editable through the Inspector of Foo?
     
  2. oxl

    oxl

    Joined:
    Nov 21, 2008
    Posts:
    325
    Hi, try putting [System.Serializable] before your struct :

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class Foo : MonoBehaviour
    6. {  
    7.    [System.Serializable]
    8.    public struct Bar { public int a; public float b; }
    9.    public Bar m_bar;
    10. }
    11.  
    12.  
    That way worked for me with classes, I think it should work with structs too.

    --
    oxl
     
  3. Jim Offerman

    Jim Offerman

    Joined:
    Jul 17, 2009
    Posts:
    177
    That doesn't appear to work for structs, but I can live with Bar being a class instead. Thanks!
     
  4. oxl

    oxl

    Joined:
    Nov 21, 2008
    Posts:
    325
    Hm, thats odd. I wonder why it's not possible to expose every type to the inspector. Byte turns out as a boolean for example.

    --
    oxl
     
  5. tbryant

    tbryant

    Joined:
    Aug 12, 2009
    Posts:
    17
    Struct wasn't visible in the editor, but a class worked fine. Thanks for the help.
     
  6. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    Yeah, the [Serializable] attribute doesn't work with structs; they can't be viewed in the inspector or saved with the scene (AFAIK, at least).

    I'm sure there's a technical reason for this, but I'll admit that I don't know what it is. Since Unity's own struct types (Vector3 and so on) serialize just fine, presumably there's some way to do it.

    It would definitely be useful to be able to serialize struct types in C#, but as far as I know this functionality isn't available.
     
  7. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    structs are by val, never by reference.

    that reduces their use greatly.

    stuff you intend to store within the editor are optimally extends of ScriptableObject

    You can easily work with them and setdirty from custom editor will mark them for storage towards unity if you have them on a corresponding GO.

    I've written a few task specific custom editors for levels, enemy templates and similar that use that approach and they work all fine :) (and good thing is if you forget the editor you can always doubleclick them as they will appear in the editor and they show up in an own editor with their values, for example if you have them in an array of xxxx :) that can be important for designers for example for fast changes etc)
     
  8. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    No one said otherwise.

    Not sure what you mean by this. How does making a type a value type reduce its usefulness?

    What about classes that you intend to use within a class that inherits from Monobehaviour? Something like:

    Code (csharp):
    1. public class MyComponent : MonoBehaviour
    2. {
    3.     [Serializable]
    4.     public class MyClass
    5.     {
    6.         // Stuff...
    7.     }
    8.  
    9.     public MyClass myStuff;
    10. }
    I assume there's nothing wrong with doing this?

    Anyway, I'm curious as to why you think being able to serialize (custom) value types wouldn't be useful. I know it would've been useful to me on more than one occasion, but maybe I'm missing something.

    [Oops, this is an old thread...]
     
  9. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    In this case a lot as the editor would have to dublicate it everytime it has to update that object as the interface would need to serialize / reflect it as it can not just hold a reference to it. And you would want a lot but not make the ram situation any worse than it gets with some reasonable amounts of media actually.


    Don't see anything wrong directly, but would explicitely extend it from System.Object there likely to prevent its rooting to UnityEngine.Object if you don't intend to use any of the aspects from that end.
     
  10. ToreTank

    ToreTank

    Joined:
    Jun 23, 2008
    Posts:
    165
    Not being able to expose custom structs in the editor (afaik) has been a recurrent annoyance for me too. Built-in structs such as matrices, vectors and quaternions are serialized properly, without that being a noticeable problem. I'm not sure I follow your serialization/reflection/RAM logic, though. Do you mind elaborating?
     
  11. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    I might be wrong on that end, but to my understanding, you would want customeditor support too, otherwise the exposure would be halfbaken / nil baken and for custom editors to operate on it, they need to aquire a reference to it which with structs won't go anywhere. to explain that better: I expect it to pass it between properties and real functions 1+ times, and each of that cases will result in a copy, every time the data is updated

    Question is what are you using structs for, whats the direct benefit for you using by val and copying it on every passing on over having it as a class? (the only benefit I'm aware off is commonly avoiding cache misses when the cpu goes through the content of a struct, but anything that could be editor exposed can't be large enough to trigger such a thing independent of class or struct likely)

    it might also potentially be related to UnityScript which has no structs
     
  12. ToreTank

    ToreTank

    Joined:
    Jun 23, 2008
    Posts:
    165
    How is this different from exposed custom classes? I don't see why you need a reference to it rather than working directly with a copy/the value itself. I might not have thought this through thoroughly, though.

    Structs are useful for small "container"-type value types that you copy around a lot, much like you would use a primitive like a float or int (which I guess is why they're used for vectors and alike), and they are handy because they are copied on assignment so you don't have to worry about copying each component manually or create copy constructors. There's also the benefit of them not ending up on the heap for the garbage collector when using them in intermediate calculations.

    You UnityScript argument seems valid, and that might be the reason :)

    Edit: Did you edit your post recently, or did I screw up when quoting? :) Anyway, I think the main points still stand.
     
  13. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    classes are by reference so passing around a class is a managed pointer, 4byte
    passing around a struct is x bytes where x is the size of the struct.
    You commonly don't pass single values through the whole editor, it will work with the object and extract the values from that one.

    if you naturally want them to copy around its an easy and performant way to do so :)
     
  14. ToreTank

    ToreTank

    Joined:
    Jun 23, 2008
    Posts:
    165
    Damn, you are quick on these forums, I should have guessed looking at your post count :D

    I just wanted to add that there is the possibility of passing structs around using the "ref" keyword, in which case it will not result in a copy but a reference pass. I can't help thinking that most structs are small enough to this not really being an issue. It would just be nice and handy with serializable/editor exposed structs at times, that's all :)
     
  15. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    agreed, it would be nice if it "ate them all" given you don't hang [Serializable()] in for a unityengine object in which case it will not work (as they are not serializable)

    the ref is a valid point otherwise, but in this case its the same path both go, object and structs so unsure if ref would really solve more problems than it creates.

    but in the end there are ways to achieve nearly everything aside of structs and generics at all in the editor (it was built around unity scripting and .net 1.1 logics a lot from what I've seen so far. the new gadgets etc from 2.5+ don't change anything on that end)
     
  16. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    To be clear, I'm sure there's a good technical reason why serialization isn't supported for structs. I don't know how Unity's serialization system works under the hood, so I wouldn't presume to say that struct serialization should or should not be supported.

    What I remain curious about though is how/why Unity's own value types such as Vector3 are serializable. I'm guessing they're just handled as a special case internally, and that whatever provisions are made for them can't easily be extended to other custom value types.

    I do have to question though the assertion that one should just use classes or that being able to serialize structs wouldn't be useful. C# has both reference and value types for a reason (IMO), and both have their place.

    I think the most effective way to make my argument might be to ask the following questions:

    1. Does it make sense that UnityEngine.Vector3 is a value type rather than a reference type?

    2. Is it useful to be able to serialize UnityEngine.Vector3?

    If your answer to both of these questions is yes, then I'd think you'd have to concede that being able to serialize value types can be useful. (Again though, maybe I'm missing something.)
     
    GregoryFenn likes this.
  17. Rafes

    Rafes

    Joined:
    Jun 2, 2011
    Posts:
    764
    Ack. I really needed to show a struct. I don't want to send a reference to a target when it is hit by a weapon, I want to send a struct that holds the relevant information. I want to set this in the inspector though too....back to the drawing board.
     
  18. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Are you sure? I can't think of a reason why you wouldn't use a class. It hold relevant information just as much as a struct does. It sounds like you should use a class anyway; structs should be used for very simple data only (such as a Vector3).

    I know this post is almost a year old, but it's still wrong. :) UnityScript has structs and has had them since before Unity 3; making a class extend System.ValueType makes it a struct. Kind of ugly (would be nice if you could just write "struct"), but it works fine.

    --Eric
     
  19. RElam

    RElam

    Joined:
    Nov 16, 2009
    Posts:
    375
    Yea, when I ran across this thread I was thinking the exact same thing, well said. The crucial difference is reference types require indirection, and indirection costs CPU. In the vast majority of cases, you shouldn't concern yourself with that, but 'vast majority' is not the same as 'all', and in some cases the CPU cost of that indirection is substantial. The value types used by Unity are structs for a very good reason, and that's that they are closer to 'primitives' than 'classes'. They're generally small, often put into arrays, and almost never would you want them to actually be reference based (vector3 for instance, you almost invariably want embedded). The idea that only Unity's constructs are valid as structs is pretty naive, IMO. Note, Unity's particles are also structs, far from a 'small' class by most standards, but it's still a struct for good reason.

    I'm pretty sure this is not a design choice by Unity, but a production choice, supporting this is likely just being out prioritized, for better or worse.
     
  20. yoyo

    yoyo

    Joined:
    Apr 16, 2010
    Posts:
    112
    Necropost, but still a current issue (as of Unity 4.3.1).

    Structs are undeniably useful. One thing you can do with structs that you can't do with classes is allocate a large array of them as a single consecutive block of memory. You can then pass around references (ref parameters) into this pool to avoid the copy-to-pass-value semantics of struct. It's not as clean as class semantics, but gives you better control over memory management, which is occasionally important. (Sure, you can allocate an array of classes, but all you get is an array of null references to classes, you still need to allocate each instance. If you allocate an array of structs, you've got the structs themselves.)

    As to why Unity can serialize Vector3's but not our structs, it's because Vector3 (and Vector2 and Vector4 and a few other types) are special-cased, as is evident from, for example, the existence of SerializedProperty.vector3Value.
     
    FuriantMedia likes this.
  21. Flipbookee

    Flipbookee

    Joined:
    Jun 2, 2012
    Posts:
    2,798
    Large array of structs in a single consecutive block of memory is exactly what I needed. Too bad Unity won't serialize structs :( so I have to use classes instead which not only adds one additional level of indirection but also places each instance on random locations in memory! Then processing all instances sequentially trashes all levels of memory caches leading to waste of performance. I'll have to copy all class instances into array of structs containing the same fields to avoid this ;(
     
  22. noio

    noio

    Joined:
    Dec 17, 2013
    Posts:
    232
    I know I'm resurrecting a topic, but I ended up here through search. As of this date, doing

    Code (CSharp):
    1. [System.Serializable]
    2. public struct PlayerStats
    3. {
    4.     public int moveSpeed;
    5. }
    makes this show up in the editor fine.

     
  23. Limesta

    Limesta

    Joined:
    Mar 30, 2014
    Posts:
    4
    Want to re-resurrect, I have also gotten this to work, I got allot of errors, but I copy and pasted your code, swapped some stuff, deleted your code and put in my own and it works,





    EDIT: I would also like to note that structs in structs work also, very good for organization!


     
    Last edited: May 31, 2015
    TurleyE, hernan_arga and JoeStrout like this.
  24. RealSoftGames

    RealSoftGames

    Joined:
    Jun 8, 2014
    Posts:
    220
    public people[] person;


    [System.Serializable]
    public struct people
    {
    public string name;
    public int age;
    public Gender gend;
    }
     
  25. almo

    almo

    Joined:
    Jul 14, 2010
    Posts:
    83
    This works for me. Without [SerializeField] I didn't see them in the editor.

    Code (csharp):
    1.  
    2.    [System.Serializable]
    3.    public struct MeshEnumToNameLink
    4.    {
    5.      [SerializeField]
    6.      CharacterMeshNameEnum EnumValue;
    7.      [SerializeField]
    8.      string StringValue;
    9.    }
     
    Orrib likes this.
  26. Dave-Carlile

    Dave-Carlile

    Joined:
    Sep 16, 2012
    Posts:
    967
    You would need to make the members public in order to see them in the editor without using SerializeField. Private members aren't serialized by default.
     
  27. ismaelnascimentoash

    ismaelnascimentoash

    Joined:
    Apr 2, 2017
    Posts:
    30
    Its work for me !
     
  28. WidmerNoel

    WidmerNoel

    Joined:
    Jun 3, 2014
    Posts:
    66
    Marking the struct as [Serializable] and the private field within my MonoBehaviour as [SerializeField] works for me as well. Just make sure your struct fields are mutable (i.e. not readonly). That screwed me over at first.
     
  29. rossi42

    rossi42

    Joined:
    Aug 14, 2019
    Posts:
    1
    Reviving a zombie but just wanted to add this even works with struct arrays like a charm:


    [System.Serializable]
    public struct Segment
    {
    [SerializeField] public float start;
    [SerializeField] public float end;
    [SerializeField] public int nextSegment;
    }

    public class Test : MonoBehaviour
    {

    public Segment[] segments;
    [...]

    Result in IDE:
    upload_2022-1-19_21-1-0.png
     
    nhatnhiemmo likes this.
  30. RendergonPolygons

    RendergonPolygons

    Joined:
    Oct 9, 2019
    Posts:
    98
    @rossi42 didn't work for me, even removing the constructor
    Code (CSharp):
    1. [System.Serializable]
    2.     public struct WorldSize
    3.     {
    4.         [SerializeField] public int x,y,z;
    5.         public WorldSize(int x, int y, int z)
    6.         {
    7.             this.x = x;
    8.             this.y = y;
    9.             this.z = z;
    10.         }
    11.     }
     
  31. Calihrymn

    Calihrymn

    Joined:
    Jan 15, 2020
    Posts:
    1
    Returning to this absolute relic of a forum to hopefully help someone in future, cause this took me a solid evening to discover:
    Structs cannot be serialized if you've marked them as static.
    This works for me:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class WeaponData : MonoBehaviour
    6. {
    7.     [System.Serializable]
    8.     public struct Gun {
    9.         [SerializeField] public Transform model;
    10.         [SerializeField] public float magCapacity;
    11.         [SerializeField] public float recoil;
    12.         [SerializeField] public float rateOfFire;
    13.     }
    14.     [SerializeField]
    15.     public Gun glock17 = new Gun();
    16. }
    17.  
    but this didn't:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class WeaponData : MonoBehaviour
    6. {
    7.     [System.Serializable]
    8.     public struct Gun {
    9.         [SerializeField] public Transform model;
    10.         [SerializeField] public float magCapacity;
    11.         [SerializeField] public float recoil;
    12.         [SerializeField] public float rateOfFire;
    13.     }
    14.  
    15.     [SerializeField]
    16.     public static Gun glock17 = new Gun();
    17. }
    18.  
     
    torantt likes this.
  32. MartinMa_

    MartinMa_

    Joined:
    Jan 3, 2021
    Posts:
    455
    This is a working solution.

    Code (CSharp):
    1. [Serializable]
    2. public struct BuildingControls
    3. {
    4.     public KeyCode removeAllSelectedPlatforms;
    5. }
    6.  
    7. [SerializeField] public BuildingControls buildingControls;
     

    Attached Files: