Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

[Released] Adic - Dependency Injection Container

Discussion in 'Assets and Asset Store' started by Intentor, Mar 18, 2015.

  1. Raidenwins

    Raidenwins

    Joined:
    Dec 18, 2012
    Posts:
    132
    Hmm yea, that's why I had my bindings arranged the way they were originally. In other words, since MyClass uses MyFirstMonoBehavior and MySecondMonoBehavior uses both MyClass and MyFirstMonoBehavior, I had MyFirstMonoBehavior first, MyClass second, and MySecondMonoBehavior last.

    Once I placed MyClass above MyFirstMonoBehavior like you suggested though, everything works fine, which is good, but it's puzzling to me as I don't understand how MyFirstMonoBehavior gets injected into MyClass if it's placed after it. Particularly since the constructor injection into MyClass happens before the method injection into MySecondMonoBehavior. Could you explain that?
     
  2. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello, @Raidenwins!

    It's magic! :p

    However every magic has an explanation! ;)

    The injection on MonoBehaviour doesn't occur during binding time, but when some form of behaviour injection is used (in your case, probably through the calling of the Inject() method during Start()). When injection takes place, any members annotated with [Inject] attributes are injected from every container available on the scene.

    To better understand when Adic events are called, take a look at order of events at the docs.

    Hope that helps clarify the issue!
     
  3. Raidenwins

    Raidenwins

    Joined:
    Dec 18, 2012
    Posts:
    132
    Haha I like it. It is kind of magic. Thanks for that! :D
     
  4. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    The 2.24 version is available on the Asset Store.

    Changelog

    Framework
    • Added exception when trying to instantiate interfaces.
    • Added injection on acessors only if no value has been injected. [Issue #73]
    • Fixed NullReferenceException when disposing containers. [Issue #74]
    • Fixed throwing exception then readding extensions.
    Bindings Printer Extension
    • Added container identifier.
    Context Root extension
    • Added container identifier overload when adding containers.
    • Added container resolution mode overload when adding containers.
    Event Caller extension
    • Fixed disposing of IDisposable objects when unregistering the extension. [Issue #75]
    • Fixed LateUpdate not working for resolved instances. [Issue #77]
    • Fixed UnityEvents context root class on scene.
     
  5. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    The 2.25 version is available on the Asset Store.

    Changelog

    Framework
    • Addded initialize event to containers and extensions. [Issue #80]
    • Addded includeChildren to ToNamespace and ToNamespaceSingleton. [Pull request #81]
    • Improved messages when an InjectorException occurs. [Pull request #82]
    • Improved chaining on containers. [Issue #78]
    Bindings Printer Extension
    • Fixed instance hash code display for bindings. [Issue #79]
    Commander extension
    • Added late binding to allow command registration in any order. [Issue #80]
     
  6. Raidenwins

    Raidenwins

    Joined:
    Dec 18, 2012
    Posts:
    132
    @Intentor I am having problems with manual type resolution. I am trying to do the following:

    This is in my ContextRoot class:
    Code (CSharp):
    1. public override void SetupContainers()
    2.     {
    3.         var container = this.AddContainer<InjectionContainer> ();
    4.  
    5.         container
    6.             .RegisterExtension<EventCallerContainerExtension> ()
    7.             .RegisterExtension<UnityBindingContainerExtension> ()
    8.             .Bind<TestClass> ().ToSelf ();
    9.     }
    And in TestClass:
    Code (CSharp):
    1. public class TestClass
    2. {
    3.     [Inject]
    4.     public IInjectionContainer container;
    5.  
    6.        void TestMethod()
    7.        {
    8.             container.Resolve<SomeType>();
    9.        }
    10.  
    11. }
    The problem is that container above is null. Why is that happening?
     
    Last edited: Mar 19, 2017
  7. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello @Raidenwins!

    The problem may be that you're not resolving the class.

    For a regular class to receive the injections, it has to be injected (just like with behaviors). When you just bind them to the container without being singleton, the class is never resolved and hence injected. The code below will work:

    Code (CSharp):
    1. using UnityEngine;
    2. using Adic;
    3. using Adic.Container;
    4.  
    5. namespace Adic.Examples.Testbed {
    6.     /// <summary>
    7.     /// Game context root.
    8.     /// </summary>
    9.     public class GameRoot : ContextRoot {
    10.         public override void SetupContainers() {
    11.             var container = this.AddContainer<InjectionContainer> ();
    12.  
    13.             container
    14.                 .RegisterExtension<EventCallerContainerExtension> ()
    15.                 .RegisterExtension<UnityBindingContainerExtension> ()
    16.                 .Bind<TestClass>().ToSelf();
    17.  
    18.             // Resolve the class and call the method. Injection will be performed.
    19.             container.Resolve<TestClass>().TestMethod();
    20.         }
    21.  
    22.         public override void Init() {
    23.             // Init the game.
    24.         }
    25.     }
    26.  
    27.     public class TestClass {
    28.         [Inject]
    29.         public IInjectionContainer container;
    30.  
    31.         public void TestMethod()  {
    32.             UnityEngine.Debug.Log(container);
    33.         }
    34.     }
    35. }
    If TestClass is injected into another class, it'll also be resolved and injected.

    Hope that helps!
     
  8. Agustin-Petrini845

    Agustin-Petrini845

    Joined:
    Oct 27, 2012
    Posts:
    2
    Hey Intentor,

    How would you go about dealing with ScriptableObjects?
    There's some Data examples but those are represented by classes, which is on first glance kinda weird.
    Could you add an example on how to read data from scriptable objects?
    The first way that comes into my mind to access a so is to have a monobehaviour wrapped around it. Is there a better way atm?

    Also, Unity discourages the usage of Resources and has been trying everyone to move towards Asset Bundles. Maybe add or modify your examples to use those instead?

    Thank you!
     
  9. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello @Agustin-Petrini845!

    When using ScriptableObjects with Adic, you can first load them from an Asset Bundle (or the not so nice Resources folder) or add them directly through properties on the context root (which I don't encourage), binding them afterwards.

    I'm currently planning a new way to manage Unity objects on Adic without scripting, creating a BindingSetup directly through the ContextRoot on Inspector, so it'll be easier to add ScriptableObjects (the issue https://github.com/intentor/adic/issues/86 was created to handle that).

    About the Resources folder, I'll replace all examples with Asset Bundles example (issue https://github.com/intentor/adic/issues/87). Thank you for the heads up!

    Hope that helps!

    If you have any other questions, just reply to the topic!
     
  10. Agustin-Petrini

    Agustin-Petrini

    Joined:
    Nov 16, 2012
    Posts:
    25
    Hey Intentor,

    Thanks for the reply.
    I managed to load a scriptable object without a problem, and looking forward to see some Asset Bundle examples.
    I see you are using resources load extensively within the framework (IE: in the implementation of ToPrefab).
    Wouldn't make more sense to have a base ToPrefab implementation that takes a prefab as parameter rather than an object name to be loaded from the resources folder?
    ATM this can be done by creating a prefab binding and manually adding it to the container, but I feel like having ToPrefab(GameObject prefab) it's a lot more intuitive. Then, if you want, you can have ToPrefab(string prefabName) that loads the resources and calls ToPrefab(GameObject prefab).

    If it were me though, I would stay away from using resources as it's not encouraged by Unity at all.
    https://unity3d.com/learn/tutorials/temas/best-practices/resources-folder

    "2.1. Best Practices for the Resources System
    Don't use it."

    I'm really liking your framework, it's the simplest and cleanest out there.
    Keep up the good work,

     
  11. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello @Agustin-Petrini!

    Good point about the ToPrefab implementation. I opened the issue https://github.com/intentor/adic/issues/88 to add the feature.

    About the use of Resources on the framework, it's only used on the Unity Binding Extension - at the time of its development (2014-2015) it was a sound approach. I'll rethink it, but probably the Resources calls will be kept for now to prevent breaking changes.

    And I'm glad you're enjoying Adic! It was created to be as simple as possible! :D

    Thank you for your feedback, and if you have any other questions, just reply to the topic!
     
  12. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello @Agustin-Petrini!

    If you want to check it out, the implementation of ToPrefab(GameObject)/ToPrefabSingleton(GameObject) is available on the develop branch of Adic!
     
  13. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    The 2.26 version is available on the Asset Store.

    Changelog

    Framework
    • Added inject on private members. [Issue #85]
    • Fixed resolution of arrays. [PR #83]
    Commander extension
    • Added tag when dispatching commands. [Issue #52]
    • Added release of commands by tag. [Issue #52]
    • Added chaining of release methods. [Issue #52]
    Unity Binding Extension
    • Added a ToPrefab implementation using GameObject. [Issue #88]
    • Added a ToPrefabSingleton implementation using GameObject. [Issue #88]
    • Updated ToGameObject to add a new GameObject when the given name is not found.
    • Marked all methods that use Resource loading as obsolete to comply with Unity guidelines. [Issue #88]
     
  14. TokyoDan

    TokyoDan

    Joined:
    Jun 16, 2012
    Posts:
    1,080
    A student used Zenject for his Bachelor’s thesis rather than Adic because Adic requires this.inject() be used in MonoBehaviours' Start() method:

    Code (CSharp):
    1.         protected void Start() {
    2.             // Call "Inject" to inject any dependencies in the component.
    3.             // In a production game, it's useful to place this in a base component.
    4.             this.Inject();
    5.         }
    See 8.2 Tools and Technology in the linked PDF.
    Dependency Injection in Unity3D
    Also here is the game project (MirrorPuzzle) on Github.
     
  15. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello, @TokyoDan !

    I'm glad to know somebody used Adic as part of their thesis! Thank you for sharing! :)

    (A nice thesis by the way - I've just finished reading it!)

    Since 05/01/2016, more than a year before the aforementioned doc was released (which is dated March/2017), Adic provides a scene wide injection that doesn't rely on manual injection for every MonoBehaviour (so, no this.Inject() on Start() methods) which is the way I currently recommend Injection is performed.

    I've created an issue to update all examples with this approach, further clarifying this recommendation.

    Additionally, I'm working on version 3 of Adic, which will simplify injection even more by allowing full container configuration through inspector, without any custom code. Stay tuned! ;)
     
  16. TokyoDan

    TokyoDan

    Joined:
    Jun 16, 2012
    Posts:
    1,080
    Great news. Thanks. Actually I emailed the writer of that thesis asking him about some details.

    (You know. It'd be great if you could make an Adic implemention of his Mirror Puzzle game. I was about to try but I still don't understand either Adic or Zenject to do it myself.)

    Below is my correspondence with the thesis writer:
    ------------------------------------------------------------------------------------
    Hello,

    I am reading reading your excellent paper on Dependency Injection in Unity3D.
    I got a few questions about the Mirror Puzzle implemention. You wrote:

    "Adic was the first choice for dependency injection container. It has method descriptions available in IntelliSense and is very well documented, however, it requires a separate Inject method call in MonoBehaviour Start methods which eventually lead to change the choice of the dependency injection container to Zenject."

    1. Why did the Adic's separate inject method call in Start methods sway you to use Zenject?
    2. Is that separate inject method call a bad thing or impossible to use in your game?
    3. It it possible for me to switch Adic for Zenject in your game example?

    Kindest Regards,
    Dan Huffman
    ------------
    Hello,

    I'm glad to hear the paper is of some use.

    1. It was simply a personal choice. If I remember correctly, Adic's documentation guided to create a base class where the Inject method would be called and then use this base class for each MonoBehaviour. For me, this felt cluttering.

    2. I don't think it that it would create any real problems. Using a DI container already ties your code with that specific DI container a bit, so having that extra call there, would not be that big issue. The example would work just fine with Adic instead of Zenject.

    3. You probably can, but the amount of work required to do that is unknown for me. You probably don't need to touch the game scripts that much (except get that extra Inject method call there). The Installer scripts have to be rewritten for Adic. Most work would probably be with the prefabs and Game Objects in Unity editor as they have Zenject's components attached to them.

    I hope these answer your questions.

    ------------------------------------------------------------------------------------
     
  17. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello, @TokyoDan!

    Interesting answers! Glad that you contacted him. I've emailed him too, and he was also very kind.

    I've looked into the Mirror Puzzle game, checking about implementing it using Adic. It's a relativelly simple implementation, but unfortunatelly I can't afford the time to do it right now. Basically, what needs to be updated:

    1. Create a copy of the ZenjectPrototype folder, renaming it AdicPrototype;
    2. Update all namespaces to AdicPrototype;
    3. Change Zenject namespaces to Adic (in some cases minor changes are required;
    5. Replace all Zenject installers to Adic BindingsSetup;
    4. Create Adic context root, with a single container adding bindings from the BindingsSetup namespace;
    6. Remove all Zenject components from the prefabs, adjusting code when required.
    7. Play!

    The gameplay code itself won't require any major changes.

    I've also checked the thread you created about the thesis. An interesting (and argumentative) read! :)

    If you have any questions about Adic, just let me know!
     
  18. TokyoDan

    TokyoDan

    Joined:
    Jun 16, 2012
    Posts:
    1,080
    Thanks for the pointers. That will make an interesting project and help with learning Adic.
     
  19. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello, @TokioDan!

    I'm always happy to help! :)

    If any questions arise during your studies with Adic, just reply to the topic!
     
  20. Richy19

    Richy19

    Joined:
    Apr 19, 2013
    Posts:
    2
    Hey there @Intentor, Been keeping an eye on this for a little while and am now starting a new project that I can actually make use of DI for!

    I had a couple of questions,
    releases were happening every few weeks but the project has been quiet for 2 months, how stable is the current build?
    Also, I really like the fact ADIC is build into 3 simple DLL's, but I wanted to ask if you had any experience in terms of performance of ADIC vs Zenject, do you know of any reasons to chose 1 over the other?
     
  21. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello, @Richy19!

    Thank you for considering Adic for your next project!

    I may look biased when speaking about Adic (for being it's creator) but I do enjoy developing with it. It's simple to use, little invasive to the project and has great performance - these are always the focus when developing the component.

    Although I've never released a comparison chart against other DI containers, I've tested injection with other libraries and Adic is always a great performer. There are perfomance tests in the source code and details in the docs which you can use for comparison.

    I know its release schedule is not consistent, mainly due to my constrained time and working on Adic 3, but I always solve any critical bugs and answer questions as soon as they appear. Additionally, Adic is very mature on what it offers, so its core is stable (in such a way that it's being carried on mostly intact to the version 3).

    The main reason for using Adic? It's easy to use (and it's also fast and stable!). If I had to chose a single reason for even starting the project in the first place, it was to create a DI container that is just... simple.

    If you're in doubt on which container to choose, I do recommend you try the ones you liked, performing the same actions on all of them, measuring at least execution time when testing. This will allow you to analyze the components in terms of usability and performance, leading to a more educated choice on which one may suit you better.

    Hope that helps!

    If you have any further questions, just let me know!
     
  22. Richy19

    Richy19

    Joined:
    Apr 19, 2013
    Posts:
    2
    @Intentor Woa, thank you for such a detailed answer!

    I agree that ADIC looks much simpler to use, not that zenject is hard, but the way tohat contexts work for example is much simpler in ADIC. And glad to hear performance is comparable between the 2.

    I didn't know you were working on ADIC v3, is that happening on the Github?

    I did actually have another question, what is the difference between the 2 dll's on the download page in github?
     
    Last edited: Aug 22, 2017
  23. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello, @Richy19!

    Glad you enjoyed the answer! The most important thing to me when answering you is to allow you to make an educated choice among all avaliable containers. If in the end you end up choosing Adic, great! :D

    I'm working on version 3 in a separated branch locally. I'll push it soon (currently is kind of a mess)! :D

    About the DLLs, the AOT one is for using on devices that don't allow dynamic compilation (like consoles, mobile with IL2CPP and WebGL). The regular library is essentially for desktop builds (its performance is superior because it executes reflection actions using dynamic compilation directly on IL instead of C#).

    Hope that helps!

    If you have any other questions, just reply to the topic!
     
  24. faviann

    faviann

    Joined:
    Sep 9, 2015
    Posts:
    8
    Hey @Intentor, I've been looking at different DI/IoC available for Unity and since perfomance and simplicity were two big criterias I'm considering adopting Adic for our next game.

    I'm trying to find some features I can't seem to locate in the docs/examples/forums. If you could point me as to where I should read for each I'd be really grateful.

    Issues:

    1) I have 3 different Prefabs sharing the same MonoBehaviour. The MonoBehaviour needs injection for their fields. One field is of type ICommonService and the other is of type IDifferentService. I want all three instances to share binding and instance for the ICommonService field but have their own custom bindings per Prefabs/GO for each IDifferentService field.

    I was wondering if there is a way to accomplish something similar with Adic? I was thinking of injecting the root container inside factories, and creating a custom container per prefab. This would allow somekind of composition of containers while reusing bindings in the root container.

    2) I have 2 Prefabs instances with each 2 MonoBehaviours. Both MonoBehaviour requires field injection of type IService. My problem is that I would like to inject the same IService instance for the 2 MonoBehaviours on the same GameObject but a different instance for the MonoBehaviours on the second gameObject.

    These two things are my biggest issues which I'm not sure how to fix using Adic. The way I would solve this with Autofac is with lifetime scopes. You can define custom bindings for a lifetime and it can act as some sort of subcontainer. Zenject I think makes it possible by using GameObjectContext&Installers. The only thing that I could find was using the InjectFromContainer attribute which I think unfortunately doesn't solve my problem. I stumbled upon you mentionning working on subcontainers in the thread, which sounds like it could help/manage this problem but I'm guessing it's not there yet either.

    On another note, the code is really clean and simple. Congrats for that. Like Da Vinci said “Simplicity is the ultimate sophistication”.
     
  25. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello, @faviann_sauro!

    Thank you for considering Adic for your next project! :D

    Being easy to use is the main goal of Adic. I'm currently working in version 3, which will provide an even simpler interface to interact with the container!

    Until there, let me answer your questions!

    For both of your doubts Adic can help you. Basically you've to use conditions when creating the bindings:

    1) ICommonService is bound to the container regularly, while IDifferentService should be bound by a condition through identifier or instance (if you already have the prefab instances):

    Code (CSharp):
    1. // Binding by identifier...
    2. container.Bind<SomeInterface>().To<SomeClass>().As("Identifier");
    3.  
    4. /// ...or instance.
    5. container.Bind<SomeInterface>().To<SomeClass>().WhenIntoInstance(myInstance);
    2) Currently, the best way to perform injection as you need is to use conditional binding in the same way as above. In Adic version 3, the concept of subcontainer will be introduced, which will make it easier to inject without any conditions. However, you could currently create a new context root just to perform different bindings for the same types. In this case, your context root would inject only on children with those different instances.

    Hope that helps! :D

    And thank you for the compliment about code simplicity! If Adic want to be a simple library, its code should follows the lead! (And as a side note I love clean and simple code, because less code equals less bugs!) :D

    If you have any further questions, just reply to the topic!
     
    faviann likes this.
  26. faviann

    faviann

    Joined:
    Sep 9, 2015
    Posts:
    8
    Damn you're fast at answering.

    Conditions actually work great for situation 1 and I'll look into it.

    Situation #2 though, I'm not totally sure it fits. I'll rephrase the problem, just to be sure.

    I have a Prefab for an enemy with 2 MonoBehaviours. Both MonoBehaviours requires field injection of type IService. I'd like to have the same instance of IService injected in the MonoBehaviours of a game object. The constraint is to have a different instance of IService everytime a new gameObject (instance of prefab) is created. Second constraint is that they will be spawned dynamically at runtime and we don't know how many. Third constraint, I'd love the perfomance impact (mainly allocation) to be minimal.

    Now I'm not sure how conditions would solve this issue. I'm suspecting I'm either being an idiot, blind or both and the answer is there but I can't see it.
     
  27. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello, @faviann_sauro!

    Glad to know the first question can be solved with conditions!

    About the second one, now I see a different approach.

    Using the current version of Adic, the best way to achieve what you want would be using Factories. Given a factory can also receive injection, you could even inject any other objects your need to create your prefabs (in fact, you can also resolve your prefabs from the container inside the factory, adding the IService dependency manually). Give it a try! :D

    If you have any further questions, just let me know!
     
  28. evinclav

    evinclav

    Joined:
    Jul 13, 2016
    Posts:
    6
    Hi

    I am using Adic for my project and hit a slight problem and i can't seem to solve this reading documentation :)

    I bind couple of Components on objects and few singletons from non-components.

    During play, when i make change in codes, the Services bind on gameObjects are preserved, however other singleton instances are nulled :).

    I did try shared container (destroyOnLoad => false) but that did not solve the issue.
    Am i misunderstanding something fundamentally ?

    Code (CSharp):
    1. Container.Bind<SelectionManager>().ToGameObject(gameObject);
    2. Container.Bind<AbilityGroupManager>().ToSingleton();
    AbilityGroupManager is Resolved to null, after change in codes, during gameplay.

    Thank you!
     
  29. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello, @evinclav!

    Thank for using Adic!

    The behaviour you're describing is strange. Any binding that you create, if working at first, should work in subsequent plays. Maybe the problem is that you're binding the game object before binding the service it requires? (Always bind types that will be used by other types first.)

    Maybe I'm not understanding your problem, but please check if reordering the bindings solves the problem.

    Hope that helps!

    If you have any more questions, please let me know!
     
  30. evinclav

    evinclav

    Joined:
    Jul 13, 2016
    Posts:
    6
    Hi @Intentor

    The binding order is proper :) When I launch the game, everything is resolved properly. The problem occurs when I go ahead and change some codes during gameplay. Going back to unity triggers reload of codes (still gameplay is on), this is the moment where Services bound with gameObjects are preserved, however simple non-component instances are nulled.

    Simply the problem is that after each code change, i need to stop and start again the game in editor. As my references get broken : )

    [Edit]
    Apparently I have to set class as Serializable, so this Issue is probably not related to Adic. Ill investigate further and confirm this :) thanks!
     
    Last edited: Dec 18, 2017
  31. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello, @evinclav!

    When you change a script and it's recompiled, Unity reloads the updated scripts. This may cause Adic to lose references to reloaded instances. If the scene that created all the bindings is not in the current scene, most of the references can be lost.

    My recommendation, which is what I do with any script updating in Unity (not only the ones bound to Adic), is to always restart the play mode after any script update, thus preventing any loss of data or execution errors.

    Hope that helps!
     
  32. squall-leonhart

    squall-leonhart

    Joined:
    May 5, 2017
    Posts:
    26
    Hi Intentor,

    First of all thanks for this great asset. I am adopting Adic into my game. I am moving most of my logic to normal classes implementing Unity events if needed via your event callback interfaces like IUpdatabable, IFixedUpdatable etc. I like it a lot however I am wondering if there's anyway to use Coroutine (which can be replaced with simple thread most of the time) especially in the case of loading asset async-ly via AssetBundle like LoadAssetAsync where it returns a AssetBundleRequest.
     
    Last edited: Jan 21, 2018
  33. FodderMK

    FodderMK

    Joined:
    Jan 21, 2013
    Posts:
    5
    @squall-leonhart : The easiest solution is probably to use a small helper function that can manage coroutines in the Unity environment. I haven't used it but the implementation at https://github.com/appetizermonster/Unity3D-Co looks decent.

    Alternately AssetBundleRequest has an isDone property that you could check every update call and act accordingly when it's true.
     
  34. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello, @squall-leonhart!

    First of all, thank you for using Adic!

    If you're asking about using coroutines on regular classes, this is not currently possible with Adic (but it'd be relative easy to implement. I opened an issue to add it!). However, you can use them in commands.

    In terms of asset bundle, I do recommend, as @FodderMK said, to check the isDone property if you need any injections that are performed by an outside container (i.e. that is not created by game objects in the asset bundle).

    Hope that helps!

    If you have any more questions, just reply to the topic!

    And thank you for your help, @FodderMK! :D
     
  35. squall-leonhart

    squall-leonhart

    Joined:
    May 5, 2017
    Posts:
    26
    @FodderMK
    Thanks for your suggestion. The Unity3D-Co is a lightweight coroutine wrapper, very nice!. It works great with normal class and I have it in. Guess i just share the codes (nothing to shout about) here

    @Intentor
    I am the one who should thank you for the great asset. I have to admit I didn't use Adic's Command instead just bind a monobehaviour ToGameObject as the game entry point, it is too "scary" to have so much magic at one time for a slow learner like me. In regards to method injection, it would be "injected" once after constructor of a class right ? if fired twice means the method was injected twice or rather the normal class being instantiated twice?

    Code (csharp):
    1.  
    2.     public void LoadSprite(string sprtieName, Action<Sprite> spriteLoadedCallback)
    3.         {
    4.             AssetBundleManager.LoadBundle(BUNDLE_NAME, ab =>
    5.             {
    6.                 Action<Sprite> spriteLoaded = spriteLoadedCallback;
    7.                 if (spriteLoaded == null) return;
    8.                 Co.WithPermanent.Run(LoadSpriteAsync(ab, spriteName, spriteLoaded));
    9.             });
    10.         }
    11.         private IEnumerator LoadSpriteAsync(AssetBundle ab, string spriteName, Action<Sprite> spriteLoaded)
    12.         {
    13.             var request = ab.LoadAssetAsync<Sprite>(spriteName);
    14.             yield return request;
    15.             if (request.isDone)
    16.             {
    17.                 spriteLoaded.Invoke(request.asset as Sprite);
    18.                 UnloadBundle(0;
    19.             }
    20.         }
    21.  
     
  36. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello, @squall-leonhart!

    The injection on methods should occur just once (and the same is true for any other class members). If not, maybe there's a scene injection anda behaviour injection taking place together.

    If the situation persists even after checking that there's just a single injection occuring, please provide a sample project with the problem and I take a look into it!

    Hope that helps! :D
     
  37. squall-leonhart

    squall-leonhart

    Joined:
    May 5, 2017
    Posts:
    26
    @Intentor

    It was injected twice due to my codes :). I used another great asset (SimpleBind) for MVVM and it manages the instantiation and data binding of the viewmodel classes, hence all the viewmodel was not instantiated/injected by Adic's container. Due to that I created a base abstract viewmodel class and inject all the derived viewmodels with Adic, I think I show the codes better :). It works for all the derived class with the exception of the 1st view (monobehaviour) and the 1st viewmodel because for the 1st view (monobehaviour) was injected by Adic's container, then the 1st Viewmodel inject again manually, Wrong implementation right ? :D

    Code (csharp):
    1.  
    2. 1st View
    3. public class MainMenuBehaviour : MonoBehaviour // mainmenubehaviour is injected from adic's container
    4. {
    5.         [Inject]
    6.         public MainMenuViewModel DataContext { get; set; } // refer to the 1st viewmodel
    7.  
    8.         public object ActiveView
    9.         {
    10.             get
    11.             {
    12.                 return DataContext.ActiveView;
    13.             }
    14.         }
    15. ...
    16. }
    17.  
    18. 1st ViewModel
    19. public class MainMenuViewModel: ViewModelBase
    20. {
    21.         #region Dependency Injection
    22.         [Inject]
    23. #pragma warning disable 649
    24.         private IAuthenticationService _authenticationService;  // injected via ViewModelBase
    25. #pragma warning restore 649
    26.  
    27.         [Inject]
    28. #pragma warning disable 649
    29.         private ISprteManager _spriteManager; // Injected via ViewModelBase
    30. #pragma warning restore 649
    31.  
    32. protected override void Initialize()
    33. {
    34.             Debug.Log("MainMenuViewModel.Initialize"); // injected twice.. to be revisited
    35.             SetupCommands();
    36. }
    37. ...
    38. }
    39.  
    40. public abstract class ViewModelBase
    41.     {
    42.         protected ViewModelBase()
    43.         {
    44.             InjectionUtil.Inject(this); // inject to derived classes -- the "2nd" Injection for the 1st Viewmodel
    45.         }
    46.    
    47.         [Inject]
    48.         protected abstract void Initialize();
    49.    
    50.     }
    51.  
    52. Adic root
    53. public class GameContextRoot : ContextRoot
    54.     {
    55.         public GameObject MainMenuCanvasPrefab;
    56.  
    57.         public static IInjectionContainer Container { get; private set; }
    58.  
    59.         public override void SetupContainers()
    60.         {
    61.             // Create the container.
    62.             Container = AddContainer<InjectionContainer>()
    63.                 .RegisterExtension<UnityBindingContainerExtension>()
    64.                 .RegisterExtension<EventCallerContainerExtension>();
    65.  
    66.             // Bind
    67.             Container
    68.                 .Bind<AssetBundleManager>().ToGameObject()
    69.                 .Bind<ISpriteManager>().ToSingleton<SpriteManager>()
    70.                 .Bind<IAuthenticationService>().ToSingleton<GameSparksManager>()
    71.  
    72.                 //.Bind<MainMenuViewModel>().ToSingleton<MainMenuViewModel>()
    73.                 .Bind<MainMenuBehaviour>().ToPrefabSingleton(MainMenuCanvasPrefab)
    74.                 ;
    75.         }
    76.  
    77.         public override void Init()
    78.         {
    79.             // Init the game.
    80.         }
    81.     }
    82.  
     
    Last edited: Jan 23, 2018
  38. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello, @squall-leonhart!

    I think the problem occurs because both Adic and you are injecting dependencies into the object (Adic through singleton binding, you through ViewModelBase).

    One approach to solve the problem is to always bind all view models to Adic without having the Inject() method being called in your ViewModelBase. I do prefer this approach because all your ViewModels, which may require injection (and given they're not behaviours) should be managed by the container.

    You could use a Bindings Setup to look for all your ViewModels using reflection and bind them to the container without having to hand pick each one of them.

    Hope that helps!
     
  39. squall-leonhart

    squall-leonhart

    Joined:
    May 5, 2017
    Posts:
    26
    @Intentor

    Thanks for your suggestions, I tried before and got some errors, basically I think (I didn't go in-depth) the errors were the MVVM binding happened after ctor before/same time with Adic injection hence most of the visual bindings not bind-ed and resulted in errors. When time permits I will debug in-depth and will post here if any issues..

    Thanks and Regards
     
  40. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello, @squall-leonhart!

    If you need any further assistance, just reply to the topic!

    Best of luck in your projects! :D
     
  41. fakegood

    fakegood

    Joined:
    Oct 11, 2013
    Posts:
    31
    Hello, @Intentor. I am trying out Adic and got a question for you.

    I have a setup where I want to change scenes after a save file is loaded.

    Code (CSharp):
    1. ReflectionCache cache = new ReflectionCache();
    2.         IInjectionContainer container = this.AddContainer(new InjectionContainer(cache), false);
    3.         container.RegisterExtension<UnityBindingContainerExtension>();
    4.  
    5.         container.Bind<GameData>().ToSingleton();
    Given that my values are in GameData, I have this container set to not be destroyed on load.
    After I modified the value from my First Scene, and load to my Second scene, the GameData from my Second Class in my Second scene is returning the default value again.

    Can I know is this intentional (DI behaviour) or did I setup wrongly?


    Thanks! :)
     
  42. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello, @fakegood!

    All containers marked as dontDestroyOnLoad should be kept alive among scenes.

    Maybe the problem is that you're setting up new bindings for GameData elsewhere, in a way it's replacing the old one?

    If the problem persists, please attach a project so I can take an in-depth look!

    Hope that helps!
     
  43. fakegood

    fakegood

    Joined:
    Oct 11, 2013
    Posts:
    31
    Good day @Intentor

    I had the same thought too, but it doesn't work like how I expected it, so I was wondering is it a bug or just my misunderstandings haha.

    I've attached the project. Please take a look. :)

    Updated: Hello, @Intentor , just wondering is there any problem with the setup?
     

    Attached Files:

    Last edited: Jan 30, 2018
  44. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Hello, @fakegood!

    Now I understood your problem!

    You're adding the managers on different containers, so GameData is not being shared. The container in the SecondaryGameRoot is resolving a new GameData instance for the SecondMainManager object, not the same instance as in the GameRoot.

    To solve the problem, in the SecondMainManager, you should use the already available container:

    Code (CSharp):
    1. public override void SetupContainers()
    2. {
    3.     // Reusing existing container.
    4.     IInjectionContainer container = this.containers[0];
    5.  
    6.     container.Bind<SecondMainManager>().ToGameObject();
    7. }
    Currently, Adic doesn't support subcontainers or fallback containers, in a way that if a dependency is not found in a container, Adic looks into other containers (this is a feature I'm still developing). When this feature is available, what you need will be more transparent. :D

    Hope that helps!
     
  45. fakegood

    fakegood

    Joined:
    Oct 11, 2013
    Posts:
    31
    Ah ha! now that explains! :) thanks for your reply! And I'm also looking forward for Adic 3!

    Keep up the good work! :)
     
  46. Intentor

    Intentor

    Joined:
    Jul 24, 2013
    Posts:
    94
    Thank you! :D
     
  47. StormPie

    StormPie

    Joined:
    May 27, 2015
    Posts:
    1
    Hi there,

    I am having a little difficulty in configuring my dependency injections. It's actually easier to show the bits of code where I'm having the problems.

    Here is a brief overview of the setup - Hero derives from Entity. Entity has a member EntityBrain which is also IUpdatable. BattleCoordinator is a Singleton that must be injected in EntityBrain. Currently, it is not. Another weird thing is that IUpdatable works, however, when calling EntityBrain.StartBrain() the variable IsRunning is set to true but in the Update() method always stays false...

    Any help or tips would be greatly appreciated. It's 2 in the morning here and I have spent all day trying to figure this out. :(

    GameRoot.cs
    Code (CSharp):
    1.  
    2.         var container = this.AddContainer<InjectionContainer>();
    3.  
    4.         container
    5.                 .RegisterExtension<UnityBindingContainerExtension>()
    6.                 .RegisterExtension<EventCallerContainerExtension>()
    7.             .Bind<IBattleCoordinator>().ToSingleton<BattleCoordinator>()
    8.             .Bind<IEntityBrain>().To<EntityBrain>();
    9.  
    10.         // Resolve the class. Injection will be performed.
    11.         container.Resolve<IEntityBrain>();

    EntityBrain.cs
    Code (CSharp):
    1. public class EntityBrain : IUpdatable, IEntityBrain
    2.     {
    3.         public ReactiveProperty<BrainState> StateRX { get; private set; }
    4.  
    5.         public bool IsRunning { get; set; }
    6.  
    7.         [Inject]
    8.         private IBattleCoordinator battleCoordinator;
    9.  
    10.         public EntityBrain()
    11.         {
    12.             this.StateRX = new ReactiveProperty<BrainState>(BrainState.Unknown);
    13.         }
    14.  
    15.         public void Update()
    16.         {
    17.             // every update check what to do
    18.             if (this.IsRunning == false)
    19.             {
    20.                 Debug.Log("Running false");
    21.                 return;
    22.             }
    23.  
    24.             //this.DetermineState();
    25.         }
    26.  
    27.         public void StartBrain()
    28.         {
    29.             Debug.Log("Starting entity's brain");
    30.             this.IsRunning = true;
    31.             // Just for test - try to call a battleCoordinator method ( crashes -> no instance )
    32.             battleCoordinator.StartNewBattle(new BattleData(BattleLocation.Arena) );
    33.         }
    34. }
    GameTest.cs
    Code (CSharp):
    1. public void GenerateTest()
    2.     {
    3.         GameObject hero = poolFactory.GetObject("TestHero");
    4.  
    5.         IHeroView view = new HeroView(hero, hero.transform.parent.gameObject);
    6.         IHeroData heroData = new HeroData();
    7.         IHeroAnimationController animationController = hero.GetComponent<HeroAnimationController>();
    8.         IEntityBrain brain = new EntityBrain();
    9.  
    10.         IHero finalHero = new Hero<IHeroData, IHeroView>(heroData, view, animationController, brain);
    11.         finalHero.WakeUp();
    12.     }
    Entity.cs
    Code (CSharp):
    1. public abstract class Entity<D, V> : Context<D, V>, IEntity
    2.             where D : IEntityData
    3.             where V : IEntityView
    4.     {
    5.         public Entity(D data, V view, IEntityAnimationController animationController, IEntityBrain brain, int health = 100)
    6.             : base(data, view)
    7.         {
    8.             this.AnimationController = animationController;
    9.             this.Brain = brain;
    10.             this.HealthRX = new ReactiveProperty<int>(health);
    11.  
    12.             this.observables = new List<IDisposable>();
    13.         }
    14.  
    15.         public IEntityAnimationController AnimationController;
    16.  
    17.         public IEntityBrain Brain;
    18.  
    19.         public ReactiveProperty<int> HealthRX { get; }
    20.  
    21.         public void WakeUp()
    22.         {
    23.             this.Brain.StartBrain();
    24.         }
    25. }
    Hero.cs
    Code (CSharp):
    1. public class Hero <D, V> : Entity <D, V>, IHero
    2.     where D : IHeroData
    3.     where V : IHeroView
    4. {
    5.     public Hero(D data, V view, IHeroAnimationController animationController, IEntityBrain brain)
    6.         : base(data, view, animationController, brain)
    7.     {
    8.  
    9.     }
    10. }
     
    Last edited: Jan 4, 2019