Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

[RELEASED] IUnified - C# Interfaces for Unity!

Discussion in 'Assets and Asset Store' started by Roland1234, Oct 25, 2013.

  1. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Hello Unity community peoples,

    I'm just a small-fry, independent, self-proclaimed game developer who's been working in earnest on a game for the past half year or so. While working on my project I've recently come up with what I think is a real good solution to the glaring inability of not being able to expose C# interface fields in your MonoBehaviour scripts like you would other component references or primitive types. After several layers of polishing and submitting I've finally heard from the Asset Store team today that my asset has passed review and has gone live in the store! So I submit to you: IUnified - Interfaces for Unity!

    It is designed to be as simple and unobtrusive as possible to easily integrate into Unity's workflow. Features include:
    • Easily expose interface fields in your script's inspector without the need for defining a custom editor every time!
    • Assign components that implement your interface as you would any other reference - just drag and drop.
    • Custom selection list allows you to quickly pick your interface implementation from existing scene and prefab object scripts.
    • Serialized like any other reference so Unity always "remembers" the assignment.

    You basically just subclass the included generic type using your interface like so:

    Code (csharp):
    1.  
    2. [System.Serializable]
    3. public class MyInterfaceContainer : IUnifiedContainer<IMyInterface> { }
    4.  
    And that's it! Now you can have MyInterfaceContainer type fields in your script and they'll automatically be drawn using the supplied custom property drawer that exposes the above listed functionality.

    Code (csharp):
    1.  
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class MyScript : MonoBehaviour
    6. {
    7.     public MyInterfaceContainer InterfaceField;
    8.  
    9.     public List<MyInterfaceContainer> InterfaceListField;
    10. }
    11.  
    I hope you all find this as useful as I have so far. I'm asking $5 for the work I've put in with the hopes of further funding the development of my game - so when buying my asset you will also help a game to be made as an added bonus! Mathematical!

    Links!
    View attachment $readme.pdf
    Asset In Store
    Website

    Many thanks for your time and attention - post any questions or comments you'd like and I'll try to respond as best I can.
     

    Attached Files:

    Last edited: Mar 7, 2014
  2. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    I should mention that currently there is a limitation with not being able to use the above subclasses inside a collection - Unity will serialize/initialize the collection itself automatically, but items in the collection come through null in the process. I'm working on enabling an unobtrusive workaround for the next release, so stay tuned if you're interested in such a feature!
    Updated in version 1.1.
     
    Last edited: Nov 6, 2013
  3. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Version 1.1 was recently accepted - it introduces the ability to have IUnifiedContainer<> derived types in collections like Lists and arrays!
     
    Last edited: Nov 16, 2013
  4. AlwaysSunny

    AlwaysSunny

    Joined:
    Sep 15, 2011
    Posts:
    260
    Sounds very useful, and with a modest price. Do you have competitors in the AssetStore which accomplish something similar? I've avoided using Interfaces altogether to avoid the headaches this supposedly solves, so I'm quite interested. Can you please describe what you mean by the following? Explain it like I'm five, I'm rather confused by the whole sentence:

    "Custom selection list allows you to quickly pick your interface implementation from existing scene and prefab object scripts"

    Thanks,
     
  5. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Hey Sunny!
    As far as I know there aren't any other assets in the store that offer a solution to integrate interfaces into Unity - like you say most people quickly learn to avoid them altogether when developing in Unity. I thought I came up with a reliable and generic enough solution to the problem that I decided to put it out there and potentially generate some funding for my projects.

    About the selection list: It's essentially my version of the built-in object selector (the little ◉ button next to object references in the inspector that lets you pick from a list of objects of the type in question) which lets you pick components that implement your interface. Like so:
    $Screen4.jpg
     
    Last edited: Mar 7, 2014
  6. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Version 1.2 has just been accepted (alot sooner than I thought) - its updated to work with Unity 4.3 to make it unnecessary to have to decorate fields with the [IUnifiedContainer] attribute.

    I've also introduced an implementation of IList<T> that can be used to abstract the use of a container derived object away so that given a script like this:
    Code (csharp):
    1.  
    2. using System.Collections.Generic;
    3. using Assets.IUnified;
    4. using UnityEngine;
    5.  
    6. public class MyScript : MonoBehaviour
    7. {
    8.     public IList<IMyInterface> MyInterfaces
    9.     {
    10.         get
    11.         {
    12.             return _interfaceList ?? (_interfaceList = new IUnifiedContainers<MyInterfaceContainer, IMyInterface>(() => _interfaces));
    13.         }
    14.         set
    15.         {
    16.             _interfaces = value.ToContainerList<MyInterfaceContainer, IMyInterface>();
    17.         }
    18.     }
    19.     private IList<IMyInterface> _interfaceList;
    20.  
    21.     [SerializeField]
    22.     private List<MyInterfaceContainer> _interfaces;
    23. }
    24.  
    would allow you to directly access your interface implementation in a collection like this:
    Code (csharp):
    1.  
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class MyOtherScript : MonoBehaviour
    6. {
    7.     public MyScript MyScript;
    8.  
    9.     public void Update()
    10.     {
    11.         foreach(var myInterface in MyScript.MyInterfaces)
    12.         {
    13.             myInterface.InterfaceMethod();
    14.         }
    15.     }
    16. }
    17.  
     
    Last edited: Nov 23, 2013
  7. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Just to let people know: there seems to be a problem produced by Mono when using the null coalescing operator (??) and targeting the Web Player in Unity. Replacing their instances with the conditional operator (?:) where possible or explicit if/else statements avoids the issue.

    I've submitted a fix related to this issue for version 1.2.1 which is now pending review.
     
  8. Remiel

    Remiel

    Joined:
    Oct 17, 2012
    Posts:
    105
    Can classes implementing the interface be of any type (eg. normal classes whose parent is System.Object) or do they need to be MonoBehaviours?
    I think a huge barrier to selling your asset is the lack of documentation. Why don't you put up that readme.pdf online? I , as a buyer, don't want to buy an asset that claims to do something, but I can't see how to use it and there aren't any tutorials, documentation or anything online.
    Also, creating a dummy blog just to have a link to submit to the asset store is not really...good...
    Why don't you create a real website, you can have it up and running for free in under 30 minutes, and you'd look much more reliable, accessible and professional? Go get free php hosting if you don't want to pay for it, install wordpress, get one of the professional looking wordpress themes (there are many), and viola!

    Not having a real website might pass for selling models because you don't really need support for them. But selling scripts is different and most people never buy scripts that don't have a reliable seller that seems to offer good support. Even if they are really reasonably priced as your own. (The price really is tempting.)
     
  9. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Absolutely, yes - anything that implements the interface can be assigned. Of course, if it isn't Component derived, like a MonoBehaviour, it won't be assignable directly in the inspector - you'll have to do that in code during runtime, but it is supported.

    I really appreciate your advice and feedback as a prospective user. My thinking was that I had come up with an acceptable solution to integrating interfaces into Unity for my personal use and was mostly curious to see how other people would react if I polished it up and submitted it to the store at an affordable price. I think you're very right though - I'll start looking into putting up a website. I've very limited web development experience so initially shied away from it, but you make it sound easy so I'll start looking into it.

    So thank you for the advice! In the meantime I'll attach the readme so you and others can have more information upfront.
    View attachment $readme.pdf
     
    Last edited: Mar 7, 2014
  10. Remiel

    Remiel

    Joined:
    Oct 17, 2012
    Posts:
    105
    You're welcome.
    Regarding the wordpress website. It might seem intimidating, but it IS really simple. Most hosts have one click installations of wordpress available so you just go to your control panel and choose where to instal it, and they do the rest for you. Once that's done you just log into your admin panel and start looking at options you have available. It is pretty user friendly so you'll pick it up pretty fast. I say that because I've never watched/read a single wordpress tutorial, I just installed it and started using it. Even if it takes you a while to get the hang of it(which it wont) you'll be glad in the end because you'll be creating your presence on the internet.

    Thank you for the readme!
     
  11. Wenzil

    Wenzil

    Joined:
    Apr 3, 2013
    Posts:
    19
    Very cool stuff, I've been pushing for something similar in this thread. I'm unfamiliar with the nitty-gritty details of editor scripting so I couldn't implement it myself. What you've got is pretty close.

    Unity's approach to game object composition is certainly an improvement over deep inheritance entity hierarchies. However, I feel like we are just one step away from game object structures that are much more robust and flexible. That step is better support for interfaces and dependency injection. Your asset is doing just that, so thank you!

    Here's some features/improvements I'd like to see:
    • In the editor, in addition to being able to inject an existing script instance, it would be nice to be able to inject scripts directly from the assets, thereby creating a new unique instance.
    • I'd like it if parent scripts could be unfolded to see/edit the injected script's properties
    • I'd like to have the option to hide the injected scripts from the gameobject's flat-list of monobehaviours, and only appear in their parent script (when unfolded)

    These improvements could lead to much more neatly organized gameobject structures in my opinion. For systems that are more delicate like Behavior Trees, this would be perfect.

    Anyway, good job on this, I hope you keep supporting it :)
     
  12. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Thanks Wenzil, I appreciate it!

    Although my original intention was to simply expose interface fields you could assign implementing MonoBehaviours to, your ideas had occurred to me and I agree would be nice to have. The main obstacle is Unity's serialization system, which is pretty closed. I've had some success implementing something like what you describe, but it involved handling the serialization myself during runtime and was a bit difficult to manage in a generic and robust way.

    Hopefully they'll open the serialization system up in the future and allow for easier and more reliable customization. Until then I've had to shelve those ideas and continue working on my project, but I'd like to revisit the concept again some day.
     
  13. Dracir

    Dracir

    Joined:
    Jan 18, 2014
    Posts:
    2
    I get
    and I'm fellowing your basic exemple

    Code (csharp):
    1. [System.Serializable]
    2. public class BasicDeath : IUnifiedContainer<DeathBehavior> {
    3. }
    The "IUnified" folder is in /asset but if i put it "Standard Assets", im getting those error :

    I just updated Unity to 4.3.3f1
    What should I do?
     
  14. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    I've seen no issue running in Unity 4.3.3f1 - was it working before you updated?
    Try deleting the entire IUnified folder and re-importing the asset. Make sure not to move it anywhere else, it should remain in "Assets/IUnified" in order to work properly.

    If that doesn't work then I'd need more details to see what's going on: What file is the error actually referencing? If it's one of yours, could you post it in it's entirety?
     
  15. Dracir

    Dracir

    Joined:
    Jan 18, 2014
    Posts:
    2
    All my scripts were in "Assets/standard assets", and the IUnified was in "Assets", there's my mistake.
    I moved everything on "Assets" and it's working.

    Sorry for the useless post.
     
  16. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Not a problem, glad to hear there's no issue for me to fix :)

    EDIT: As of the latest version, the IUnified folder can be safely moved anywhere within the project structure without causing issue.
     
    Last edited: Mar 7, 2014
  17. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    Hello! - I have been learning from your codes and following some of your approaches when it comes to using Styles and GUIs for editors. However, I think I came up on a bad habit that you've been using. Check this out.

    Try to open up the select window of IUnified - keep the window open - and then do something that triggers a recompile. You should get an error saying you shouldn't use GUI stuff outside of OnGUI.

    The reason is that one should initialize styles/gui-related stuff in OnGUI/OnInspectorGUI - Like so.

    Just thought I should let you aware of this.

    Cheers :)
     
    Last edited: Feb 2, 2014
  18. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    I like your approach! I do seem to remember having issues with GUIStyle initializations, but somehow worked them out without error by handling them the way I did. Now I'm kinda wondering why it worked for me and doesn't seem to be working for you... I'll have to look into this.

    More specific to IUnified though, were you actually able to reproduce the issue you've described? I have the select window explicitly closing itself when it loses focus and so am not able to cause any recompilation/serialization to try and reproduce the issue. If you've found a way to do so with IUnified, please let me know, aye?

    And thanks for the heads-up, I appreciate it!
     
  19. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    Yep it's reproducible - here's a video :) - Fortunately it's easy to solve. Just move all the initialization of your GUIStyles to an InitStyles method, and in OnGUI/OnInspectorGUI do a if (!hasInit) { hasInit = true; InitStyles(); }

    Cheers.
     
  20. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Ah, I see - that wouldn't have occurred to me. Many thanks for the video, that helped alot! An update has been submitted and is now pending review.
    Thanks again, vexe!
     
  21. RedVonix

    RedVonix

    Joined:
    Dec 13, 2011
    Posts:
    421
    I've integrated the IUnited solution into a product and it looks to be a pretty excellent piece of code! I'm getting stuck in one point however - how to add an object into a container. Being that these are Lists, I of course tried the following (extrapolated so you can see what I'm doing...

    Code (csharp):
    1.  
    2. // Definitions
    3. public class IRegionPoint2DContainer : IUnifiedContainer<IRegionPoint2D> { }
    4. public List<IRegionPoint2DContainer> regionPoints = new List<IRegionPoint2DContainer>();
    5.  
    6.     public IRegionPoint2D Interface
    7.     {
    8.         get{return _interface.Result;}
    9.         set{_interface.Result = value;}
    10.     }
    11.  
    12.     [SerializeField] private IRegionPoint2DContainer _interface;
    13.     [SerializeField] private IList<IRegionPoint2D> _interfacesDelegate;
    14.     [SerializeField] private List<IRegionPoint2DContainer> _interfaces;
    15.  
    16.     public IList<IRegionPoint2D> Interfaces
    17.     {
    18.         get
    19.         {
    20.             if(_interfacesDelegate == null)
    21.                 _interfacesDelegate = new IUnifiedContainers<IRegionPoint2DContainer, IRegionPoint2D>(() => _interfaces);
    22.  
    23.             return _interfacesDelegate;
    24.         }
    25.         set
    26.         {
    27.             _interfaces = value.ToContainerList<IRegionPoint2DContainer, IRegionPoint2D>();
    28.         }
    29.     }
    30.  
    31. public void example()
    32. {
    33.         RegionPointPosition2D newPoint = new RegionPointPosition2D();
    34.         regionPoints.Add(newPoint); // This Gives an Error
    35. }
    36.  
    That .Add method there gives this error:
    My initial thought there is I am trying to add the newPoint object to the regionPoints list in an incorrect fashion, though I'm not sure I fully understand how all of the above code is intended to make it so I can have a List of my interface IRegionPoint2D, as the list comes out as being for IRegionPoint2DContainer.

    A little help and pointers would be much appreciated! :)
     
  22. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Hello DCalabrese! Sorry I'm just getting back now, for some reason I didn't get an e-mail notification of your post.

    Regarding your issue: You are correct in noticing that your regionPoints List is for a container type, which is why you're getting the error when trying to add your interface implementation to it. If C# allowed for implicit casting to/from interface types then I could've included a much simpler and more elegant solution than the whole delegate list dance, but for some reason that specific functionality is forbidden in the language spec. So the solution I came up with was the IUnifiedContainers class which is an IList implementation that basically acts as a proxy to abstract the dependency on the container classes away when you want a list of an interface type exposed in the editor.

    What all that wonderful jargon amounts to practically is that you should be adding your interface implementation to your Interfaces property which, as you can see, implements IList<IRegionPoint2D> as opposed to your regionPoints which is a list of containers.

    Like so:
    Code (csharp):
    1.  
    2. using System.Collections.Generic;
    3. using Assets.IUnified;
    4. using UnityEngine;
    5.  
    6. public class RegionPointTest : MonoBehaviour
    7. {
    8.     public IList<IRegionPoint2D> Interfaces
    9.     {
    10.         get
    11.         {
    12.             if(_interfacesDelegate == null)
    13.             {
    14.                 _interfacesDelegate = new IUnifiedContainers<IRegionPoint2DContainer, IRegionPoint2D>(() => _interfaces);
    15.             }
    16.             return _interfacesDelegate;
    17.         }
    18.         set
    19.         {
    20.             _interfaces = value.ToContainerList<IRegionPoint2DContainer, IRegionPoint2D>();
    21.         }
    22.     }
    23.     private IList<IRegionPoint2D> _interfacesDelegate;
    24.  
    25.     [SerializeField]
    26.     private List<IRegionPoint2DContainer> _interfaces;
    27.  
    28.     private void Awake()
    29.     {
    30.         Interfaces.Add(new RegionPointPosition2D());
    31.     }
    32. }
    33.  
    Where the Awake method shows the example usage.

    As far as I can tell the regionPoints list field should be unnecessary (I'm assuming it's contained in a MonoBehaviour, yes?), but I don't know the details. Does that help resolve your issue? I admit that the whole delegate approach is less than ideal, I almost didn't include it in release but ended up finding it useful enough that I thought users might appreciate it.
     
    Last edited: Feb 8, 2014
  23. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    I've submitted a new version, 1.2.3, which addresses the following:

    - Added warning when setting non Component-derived implementations when application is not playing.
    - Fixed nulling-out non Component-derived implementations when application is playing from editor.
    - Fixed missing GUIStyle textures bug.

    Just to notify users experiencing issues related to the above - the fix is in review and should be out in a week or so. The changes are mostly cosmetic so not having them shouldn't derail anybody's development, but I could supply the updates ahead of time is somebody really needs them. If you discover any other issues then by all means let me know. Cheers!
     
  24. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    I've submitted version 1.3, which will introduce a few significant changes:
    • Changed backing field type from Component to UnityEngine.Object and enabled support for ScriptableObjects!
    • Replaced AutoDrawerRegistration mechanic with Unity-supported PropertyDrawer for derived containers.
    • Fixed bug preventing references to be properly set from the editor while playing.
    • Changed selection list UI to divide implementations between scene assets and project assets.
    For existing users whose builds might be affected by these changes this means that the container Component property will be changed to Object (just in case the property was being referenced in code, which is highly unlikely); the [IUnifiedContainer] attribute has been removed as it is no longer necessary which will also enable the IUnified folder to be moved anywhere in your project structure without breaking. Finally (and regrettably), previously set references will most likely be lost and will need to be reset. Apologies for that, but it shouldn't become necessary again anytime soon.

    I'd like to thank all existing users for their support and feedback - this turned out to be a pretty good month for me! I hope everyone continues to find my work in enabling interfaces in Unity useful.

    Good coding!
     
  25. HotClaw

    HotClaw

    Joined:
    May 20, 2013
    Posts:
    3
    This is the first asset I've bought on the asset store, and it certainly works as advertised. I just realised I don't actually need it in the project I bought it for, but I'm sure it will come in handy in the future!
     
  26. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @HotClaw: I still haven't needed it myself, but I actually bought it more for the knowledge - I never regretted it - I improved so much with editor scripting! - there's a very high learning value from understanding other people's code and techniques, especially if they were more experienced that you :)
     
  27. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Thanks for the support HotClaw! When I first started working with Unity I was pretty disappointed that interfaces weren't natively supported in the editor, and although there's often ways to work around this limitation it still bothered me that I had to design and work with one less tool in my bag, so to speak. I hope it does come in handy for you sometime, at least now you shouldn't have to worry about interface support being an issue.

    @vexe: How goes it vexe? Found a good way of integrating GUI layout methods with PropertyDrawers yet?
     
  28. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    Working on it - got busy a bit.

    I think you have some Texture2D leaking. I used to get these a lot - I just imported and used IUnified and got leak messages. I think they're related to the Textures you're creating for your for GUIStyles (the blue highlight, the yellow on click, etc) - I use similar techniques now for my styling. But I set the textures flags as DontSave - and also explicitly Destroy the texture once not needed from the editor window/editor.

    Hope you fix that soon.

    Thanks.
     
  29. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Oh? I thought I had that covered. I've been keeping an eye on that but I'll take a closer look at it, though if you manage to narrow it down I'd appreciate the heads up.
     
  30. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    I tried to really, but the was kinda messy I couldn't find it :D

    Let me share with you how I deal with it:

    First, the way I deal with the alternating between colors/styles, is via duos - ColorDuo and StyleDuo - basically a ColorDuo is just a class with 2 colors that I could alternate between easily - a StyleDue 'is a' ColorDuo, but has styles too. I'll share:

    Code (csharp):
    1.  
    2.  
    3. [System.Serializable]
    4. public class ColorDuo
    5. {
    6.     public ColorDuo(Color one, Color two)
    7.     {
    8.         colors = new Color[2] { one, two };
    9.         Reset();
    10.     }
    11.  
    12.     [SerializeField]
    13.     protected int index;
    14.  
    15.     [SerializeField]
    16.     private Color[] colors;
    17.  
    18.     public Color CurrentColor { get { return colors[index]; } }
    19.     public Color FirstColor { get { return colors[0]; } }
    20.     public Color SecondColor { get { return colors[1]; } }
    21.     public Color NextColor { get { index = (index + 1) % 2; return colors[index]; } }
    22.     public void Reset() { index = 0; }
    23.     protected void Increment() { index = (index + 1) % 2; }
    24. }
    25.  
    26. [System.Serializable]
    27. public class StyleDuo : ColorDuo
    28. {
    29.     [SerializeField]
    30.     private GUIStyle[] styles;
    31.     [SerializeField]
    32.     private bool texturesHaveBeenDestroyed;
    33.  
    34.     public StyleDuo(ColorDuo cd) : this(cd.FirstColor, cd.SecondColor) { }
    35.     public StyleDuo(Color c1, Color c2)
    36.         : base(c1, c2)
    37.     {
    38.         styles = new GUIStyle[2];
    39.         styles[0] = new GUIStyle(GUIStyle.none)
    40.         {
    41.             normal = new GUIStyleState
    42.             {
    43.                 background = Utils.GetTexture(c1, HideFlags.HideAndDontSave)
    44.             }
    45.         };
    46.         styles[1] = new GUIStyle(GUIStyle.none)
    47.         {
    48.             normal = new GUIStyleState
    49.             {
    50.                 background = Utils.GetTexture(c2, HideFlags.HideAndDontSave)
    51.             }
    52.         };
    53.         Reset();
    54.     }
    55.  
    56.     public bool TexturesHaveBeenDestroyed { get { return texturesHaveBeenDestroyed; } }
    57.     public GUIStyle CurrentStyle { get { return styles[index]; } }
    58.     public GUIStyle FirstStyle { get { return styles[0]; } }
    59.     public GUIStyle SecondStyle { get { return styles[1]; } }
    60.     public GUIStyle NextStyle { get { Increment(); return CurrentStyle; } }
    61.     public void DestroyTextures()
    62.     {
    63.         //Debug.Log("StyleDuo destroying textures");
    64.         texturesHaveBeenDestroyed = true;
    65.         UnityEngine.Object.DestroyImmediate(FirstStyle.normal.background);
    66.         UnityEngine.Object.DestroyImmediate(SecondStyle.normal.background);
    67.     }
    68. }
    69.  
    I then have a bunch of most-commonly used color/style duos (blue, yellow, pink, etc) - in your case, you want grey, so:
    Code (csharp):
    1.  
    2.         private static StyleDuo greyStyleDuo;
    3.         public static StyleDuo GreyStyleDuo { get { return GetStyleDuo(ref greyStyleDuo, GreyColorDuo); } }
    4.         private static StyleDuo GetStyleDuo(ref StyleDuo style, ColorDuo cd)
    5.         {
    6.             // it seems that re-creating the textures if they've been destroyed will still cause some strange leaks
    7.             // so I just re-create the whole style if the textures are destroyed
    8.             if (style == null || style.TexturesHaveBeenDestroyed) style = new StyleDuo(cd);
    9.             return style;
    10.         }
    11.  
    I have all these in a nice GUIHelper class.

    Now, when I want to use that style duo in a custom editor or something (for example):
    Code (csharp):
    1.  
    2.         GUIHelper.HorizontalBlock(something ? GUIHelper.GreenStyleDuo.NextStyle : GUIStyle.none, () =>
    3.         {
    4.             // stuff...
    5.         });
    6.  
    THEN when I'm done (in a custom editor for example)

    Code (csharp):
    1.  
    2.     void OnDisable()
    3.     {
    4.         GUIHelper.GreenStyleDuo.DestroyTextures();
    5.     }
    6.  
    That way, there should be no more leaks. 1- The textures are marked with HideAndDontSave. 2- And they're being destroyed when not needed. (I know it sounds stupid to destroy them but that's how the editor seems to like it...)

    I think this is a nice, tidy way to do the alternating - you never get lost. You always know where your stuff is getting created/destroyed. And it's easy to use. I remember that I liked very much your alternating idea but didn't like the implementation (it was a boolean hack at that time - not sure if you changed it now) - so I came up with this idea of duos.

    Hope that helps.
     
    Last edited: Mar 26, 2014
  31. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Sorry vexe, I meant to ask if you knew of a way to reproduce the texture leak notifications. I've tried several things but am not seeing any leaks - I'm fairly certain I never have. Are you sure IUnified is the cause and not some other asset or code?

    I appreciate the code though! As you say there's alot of value in seeing other people's approaches and techniques.
     
  32. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    Oh silly me - I immediately get the leaks errors as soon as I open up the selection window and select/ping something - and then Save the scene. Yes, I'm pretty sure it's because of opening that window. If I exit out Unity/enter again it will disappear (as all leaking messages normally do) when I save - but when I open the window again, they will start to appear again each time I save...

    Here - made a short video.
     
    Last edited: Mar 26, 2014
  33. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Aha! I see why I was missing them now. Thank you kindly vexe, and sorry for the trouble. The fix will be in version 1.3.3. Currently 1.3.2 is still pending review - as soon as it passes I'll submit the next version.

    Version 1.3.3 will also fix an issue with container properties in nested object hierarchies not drawing in the inspector. If anybody needs the fixes and/or doesn't want to wait for the review process just e-mail me your purchase invoice number and I'll gladly send it directly.

    Cheers!
     
  34. jerotas

    jerotas

    Joined:
    Sep 4, 2011
    Posts:
    5,572
    Looks pretty cool, although I definitely am not understanding the concept. You see, you're talking about "interface fields" and I think of interfaces as a group of methods, not fields, that a class must implement. I really have no idea what you mean by interface fields at all. Can you explain?
     
  35. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Of course - by "interface fields" I'm referring to fields that are of an interface type, as I'd refer to other fields being of an integer or string type. So, given the following definitions:

    Code (csharp):
    1.  
    2.  
    3. public interface IMyInterface { ... }
    4.  
    5. public class MyImplementation : MonoBehaviour, IMyInterface { ... }
    6.  
    7. public class MyComponent : MonoBehavior
    8. {
    9.     public IMyInterface InterfaceField;
    10.     public int IntegerField;
    11.     public string StringField;
    12. }
    13.  
    14.  
    I would say that the MyImplementation class implements the IMyInterface interface, while the MyComponent class contains an IMyInterface field. As you probably know, Unity does not serialize fields in MonoBehaviours that are of an interface type - so MyComponent.InterfaceField won't show up in the inspector, let alone be assignable by a Unity object that implements the interface.

    IUnified eases the burden of enabling that in a generic and reusable manner by providing a custom base class and PropertyDrawer. For the above example, adding and making use of the following class like so:

    Code (csharp):
    1.  
    2.  
    3. [Serializable]
    4. public class IMyInterfaceContainer : IUnifiedContainer<IMyInterface> { }
    5.  
    6. public class MyComponent : MonoBehavior
    7. {
    8.     public IMyInterfaceContainer InterfaceField;
    9.     public int IntegerField;
    10.     public string StringField;
    11. }
    12.  
    13.  
    will expose an assignable "interface field" (conceptually speaking at this point, as it is now of type IMyInterfaceContainer) in the inspector that can be assigned Unity objects which implement the interface (custom MonoBehaviours, ScriptableObjects and such). In code, you could now either access the interface by referencing MyComponent.InterfaceField.Result, or wrap a property getter around the container's Result property to return the interface and henceforth pretty much forget about the container altogether.

    Does that help clarify things?
     
  36. jerotas

    jerotas

    Joined:
    Sep 4, 2011
    Posts:
    5,572
    Yeah that sounds cool. I actually hadn't run into that problem before as I hadn't specified public fields of an interface type. I think I'll pick this up :)
     
  37. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Hurray! Do keep an eye out for updates if you do, I have Unity Pro skin support still in review and a few important fixes following that.
     
  38. Wom

    Wom

    Joined:
    Feb 7, 2013
    Posts:
    38
    If you don't like cluttering up your scripts with property getters, try using extension methods instead:
    Code (csharp):
    1.  
    2. using System;
    3. using System.Collections.Generic;
    4.  
    5. public interface ILayoutController {
    6.   void ResetWindow(string reason);
    7. }
    8.  
    9. [Serializable]
    10. public class ILayoutControllerContainer : IUnifiedContainer<ILayoutController> { }
    11.  
    12. public static class IlccExtension {
    13.   public static void ResetWindow(
    14.     this ILayoutControllerContainer container,
    15.     string reason)
    16.   {
    17.     if( container != null ){
    18.       container.Result.ResetWindow(reason);
    19.     }
    20.   }
    21.  
    22.   public static void ResetWindow(
    23.     this List<ILayoutControllerContainer> containers,
    24.     string reason)
    25.   {
    26.     if( containers != null ){
    27.       for( int i = containers.Count - 1; i >= 0; i-- ){
    28.         containers[i].Result.ResetWindow(reason);
    29.       }
    30.     }
    31.   }
    32.  
    33. }
    34.  
    35.  
    I'm not saying this is definitely better, just something I came up with. Less clutter in the real script, plus null safe invocation in the case of you not having set the interface field in the editor.

    Downside being, of course, the maintenance overhead of having to manually duplicate the signatures of the interface on the static extension class (multiple times if you want to do both lists and single values).
    I guess your preferred use would depend on how many methods your interfaces usually have versus how many other scripts you have referring to interface fields. My interfaces tend to be small and I'm already starting to use interface fields all over the place, so it's a win for me.

    P.S. How long does it usually take for assets to get approved through the store? I'm keen to get those new versions ;)
     
  39. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Yes indeedy! You could also have the container itself actually implement the interface that it's wrapping around, and basically forward the method call(s) to its Result property, doing your null checking there (if desired - often times throwing exceptions should be the more correct outcome I believe). You'd still have to implement extension methods for a collection to get the usage you've shown, if abstracting the fact that you're working with a collection is desirable.

    Usually no more than a week, though in a few instances I've had my submission approved the very next day. It's been 9 days today this time around, which is the longest I've had to wait yet. I suppose it all depends on their workload at the time and what position in their queue the submission is assigned to? A bit frustrating, I already have another update following this one that needs to go through.

    By all means e-mail me your purchase invoice number and I'll send you the latest version, I'm a bit keen myself to have another user verify that the fixes are indeed working correctly.
     
    Last edited: Mar 30, 2014
  40. refaxx

    refaxx

    Joined:
    Jul 11, 2014
    Posts:
    8
    Is there any way to integrate an interface field into a custom inspector?
    Something like EditorGuiLayout.InterfaceField() would sure be nice.
    Actually i'm searching for something like EditorGuiLayout.InterfaceList(), since i want a Collection.
     
  41. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Yes, if you're using the supplied IUnifiedContainer type as specified in the readme.pdf then using EditorGUILayout.PropertyField in your custom inspector will automatically resolve to use the supplied property drawer (whether it's a collection or not). You'll have to pass in the SerializedProperty obtained by calling serializedObject.FindProperty("MyContainerField"), which I'd recommend you call once in your custom editor's OnEnable method.
     
  42. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    To existing users,

    I've just learned that container fields declared in a base class will not render properly if they are marked as private (due to limitations of reflection that I wasn't aware of). The temporary work-around is to change their accessibility to protected, but I'll be working on a fix that should be ready soon. Send me your invoice numbers if you'd like to receive the fix as soon as it is in place without having to wait for Asset Store approval.

    Cheers!
     
  43. refaxx

    refaxx

    Joined:
    Jul 11, 2014
    Posts:
    8
    Ok, i now have this in my OnInspectorGUI function:

    serializedObject.Update();
    EditorGUILayout.PropertyField(serializedObject.FindProperty("MyContainerField"), true);
    serializedObject.ApplyModifiedProperties();

    It works, but when i select a different prefab and go back to this one, i get a NullReferenceException from IUnified/Editor/IUnifiedContainerPropertyDrawer.cs:449. When i catch the exception and leave it unhandled, everything seems to work just fine. I can select a different prefab and come back, i can even close unity and open it again. Everything stays as it was before.
     
  44. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    I've tried recreating your scenario using a custom editor as you've specified, but I'm not seeing any exceptions or unexpected behaviour. The line referenced in your exception (if you are using the latest version of IUnified) is a static property checking a static nullable field for null, which from what I can tell shouldn't even make a NullReferenceException possible - so this is very odd indeed.

    If you could send me a sample project that consistently reproduces this error I would be able to look into solving it. Or if you can think of any other details that might have something to do with it, that would be helpful too. Thanks, and sorry for the trouble!
     
    Last edited: Jul 24, 2014
  45. Hacky

    Hacky

    Joined:
    Mar 22, 2013
    Posts:
    28
    Hi Roland,

    I'm using Mac OS X and I don't see the button symbols. The buttons have only ? as caption (see picture). Also it doesn't recognize my classes which implements the interface.
    Can you solve this problem?

    Best regards,
    Hacky
     

    Attached Files:

    Last edited: Aug 7, 2014
  46. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Hello Hacky,

    I was wondering how Mac users were faring with my asset. The missing symbols in the UI seems like an issue with different charsets being used for some reason. I'll have to see what I can do to get my hands on a Mac environment to test and debug this, but that doesn't explain why your implementing components aren't being listed.

    Could you verify that you have actual instances of Component or Monobehaviour derived classes that implement your interface attached to a gameobject in the currently loaded scene (prefabs or ScriptableObjects in the project should also be listed)? Just to clarify: it's not enough to have an implementing class defined, there needs to be an actual instance of the object loaded in order for it to be referenced.

    Cheers!
     
  47. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    I managed to get Unity running on a Mac OS X environment but am not able to replicate the issue that you are seeing. I thought it might have to do with the UTF encoding of the source files, but switching between the available UTF-8 and UTF-16 encodings didn't seem to have any effect.

    It may be possible that something is modifying the editor GUI font being used, like another asset or a custom editor. To test this: Could you try creating a new project and only bringing IUnified in and verifying if the issue still occurs?

    Many thanks, and sorry for the trouble.
     
  48. Hacky

    Hacky

    Joined:
    Mar 22, 2013
    Posts:
    28
    Hi Roland,

    the graphical issue is solved in a new project, but I can't see my implementation of my interface. I uploaded my test project. Can you have a little look at this? Thank you very much. :)

    Best regards,
    Hacky

    [edit: file removed]
     
    Last edited by a moderator: Aug 8, 2014
  49. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    I'll take a look at it but please immediately remove the zip file you've uploaded. You've inadvertently exposed my asset to be freely downloaded by anyone and everyone without having payed for it: a big no-no. I'll report your post to try and get a mod's attention so that they might remove it themselves, but you should do so as soon as you possibly can.

    In the future, e-mail me your project directly or else upload a project with the asset removed (though my preference would definitely be the former).
     
    Last edited: Aug 8, 2014
  50. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Okay, I see your problem. As I had mentioned before: You need to have MonoBehaviour derived instances that implement your interface loaded in the scene in order to be able to reference them. A simple class implementing your interface will not be enough, it needs to derive from MonoBehaviour and you need an actual instance of it attached to a gameobject in the scene; just like with any regular component reference in Unity.

    So modify your example TestImpl definition from:
    Code (csharp):
    1. public class TestImpl : ITest { ... }
    to
    Code (csharp):
    1. public class TestImpl : MonoBehaviour, ITest { ... }
    And attach an instance of it to a gameobject in your scene (click the Add Component button in the inspector and select TestImpl) - then you can drag-and-drop a reference to it onto your container field, and it will also appear in the selection list.

    Regarding your graphical issue: The fact that the issue disappears in an empty project verifies to me that you have a conflicting process somewhere that is likely changing or in some other way modifying the editor GUI font - if it's a custom editor of yours you'll be wanting to reset whatever changes you've made to bring the GUI state back to what it was before your changes. If it's some other asset you have loaded then you should probably let the author know about it.