Search Unity

[RELEASED] StrangeIoC - Inversion-of-Control Framework for Unity C#

Discussion in 'Assets and Asset Store' started by srimarc, Jun 13, 2013.

  1. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    Unity...it's time to get STRANGE!
    Today, Third Motion, Inc. open sourced StrangeIoC, a super-lightweight and highly extensible Inversion-of-Control micro-framework, written specifically for C# and Unity.

    Site: http://thirdmotion.github.io/strangeioc/
    GitHub repo: https://github.com/thirdmotion/strangeioc
    Submission to Unity Store pending (will be free).

    KEY FEATURES
    • Dependency Injection
    • Shared pub/sub system
    • View mediation
    • Battle-tested architecture
    • Core binding framework
    • Multiple, modular contexts
    • Comes with two example projects to get you going
    KEY BENEFITS
    • Decoupled, modular code.
    • Rapid development.
    • Good for individuals, great for teams!
    • Works great with Unity MonoDevelop. Also works great without them.
    Dependency Injection
    Decouple all your class dependencies and write cleaner, modular code with a highly optimized Reflection/Injection system.

    Pub/sub system
    Each context features an EventDispatcher reachable by any point in code.

    View mediation
    Insulate your app from the chaos often present in views. Mediation allows clean separation of Views from Controllers and Models with no loss of capability.

    Battle-tested architecture
    Strange's architecture is based on the popular RobotLegs micro-framework. This architecture is well founded, highly proven, and lightly urges responsible development that works great for individuals or teams.

    Core binding framework
    The core of Strange is a simple, highly extensible Binder class. Extend the Binder to create decoupling models that suit your situation. Every component in Strange is an extension of Binder, so there are already many examples to follow.

    Multiple, modular contexts
    Modular contexts allow you to spin off portions of your project to different teams, then agree on an API and plug-and-play. This simplifies development and decouples whole components of the app for later re-use.

    No joke: this will revolutionize your development process.
     
    Last edited: Jun 13, 2013
  2. alewinn

    alewinn

    Joined:
    Nov 8, 2009
    Posts:
    185
    Hello Srimarc,

    I am currently trying to integrate StrangeIoC with nGUI ; do you have some recommendations with this ?

    I also adapted StrageIoC to Unity 3.5.x as the current version seems to works correctly only on 4.x, and did a Dll version for the core StrangeIoC engine.
    You'll find the two things (unitypackage for unity 3.5 and Visual C# project for StrangeIoC dll building) attached to this post.

    Edit : My current approach would be to use a Prefab that contains the whole nGUI hierarchy with a View derivated class attached to its root.
    This View derivated class would receive all the nGUI messages. The prefabs that encloses the nGUI hierarchy and this view derivates monobehaviour would be instanciated inside the scene from a public parameter of the contextView by a command (StartCommand, by example).
    Would this be the best method ?
     

    Attached Files:

    Last edited: Jun 30, 2013
  3. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    Hi alewinn,

    Actually I'm doing exactly the same thing myself! What constitutes the best way to do this could be fodder for some debate, but I don't really look at an NGUI view as being markedly different from any other view. Whatever its peculiarities, each view should be as simple, reusable and limited in responsibility as reasonable for its particular situation. Within this, consider if any of your views will want to be reusable, and therefore whether some of the peculiarities which NGUI allows (cool animations, e.g.) should be separated from the rest of the View to enhance portability.

    In the particular project I'm building, my approach to NGUI as a whole is to put the NGUI hierarchy in a separate scene with its own context (the scene gets loaded using LoadLevelAdditive()). UIContext is a self-standing application, so all the building and testing can happen without reference to the larger app. But some events — as when clicking a button loads something from the server — are sent/received using the crossContextDispatcher. This approach seems to give the parts of our app lots of autonomy, so I'm happy with it so far.

    I didn't really write Strange with 3.5.x support in mind, but we have at least one colleague using it successfully as-is in that environment. Could you describe what exactly is the issue you're encountering?

    Glad you're using Strange! It's great to hear that people are putting it through its paces!!!
     
  4. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
  5. alewinn

    alewinn

    Joined:
    Nov 8, 2009
    Posts:
    185
    Hello srimarc,

    Main problem I encontered for Unity 3.5 is that Unity 3.5 don't support namespaces, so I had to remove them, plus I had to redo the samples scenes setups. It was mostly minor problems.
    Thanks for the separated scene context, I'll try to do this.
     
  6. AnomalusUndrdog

    AnomalusUndrdog

    Joined:
    Jul 3, 2009
    Posts:
    1,553
    Thanks so much for this srimarc!

    If any of you are like me who's still wrapping their heads around the idea of inversion-of-control, here's a very good video tutorial that walks you through from concept to implementation: http://www.dnrtv.com/default.aspx?showNum=126
     
  7. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    alewinn,

    That's curious. As I mentioned we have at least one colleague using 3.5.x successfully with no change. Not sure why your situation is different, but I freely admit that supporting older versions of Unity wasn't high on our priority list. I'm glad you have a functional workaround. :)


    AnomalusUndrdog,

    Thank you, and thanks for the link. We believe that more devs understanding the advantages of IoC will lead to a stronger Unity community.
     
  8. yourpalmark

    yourpalmark

    Joined:
    May 10, 2013
    Posts:
    21
    Seriously thanks for this!

    I come from an AS3 background with lots of robotlegs experience and you just saved me a ton of time having to do something similar.
    If nothing more than creating the event bus and command map this saves time.
    Was about to use sebas77's ioc container, but yours seems way more solid and documented. I haven't put yours to the test yet, but I am happy to at least see that it approaches the subject from the same angle I'm used to and see that you've put a lot of thought and time into it.

    One minor thing that kind of annoys me... TmEvent. Horrible name. After looking at it for a few minutes, I finally realized it stands for ThirdMotion, but its not like you prefixed all the other classes, so I was trying to decipher what kind of event it was. Stick with something like DataEvent or anything non-branded since its the only class like that. Just my 2 cents.

    Anyway, like I said thats a very minor issue... overall thanks again for the work you've put into this. Looking forward to putting it through its paces in the coming weeks.
     
  9. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    yourpalmark,

    First, you're very, very welcome.

    Second, I thoroughly accept your sincere (and entirely justifiable) criticism of TmEvent. The fact was that we couldn't use 'Event' and didn't like other ideas we considered, so we used TmEvent (thinking to replace it eventually) and then it just stuck. On the plus side, note that unlike Actionscript you virtually NEVER need to reference the concrete TmEvent. When you fire an event, you simply call:

    ...or...

    and handlers should reference the interface IEvent, not the concrete TmEvent.

    So TmEvent is used internal to Strange, but doesn't really affect you outside it. (Actually, this probably accounts for why I never got around to fixing it.) Still, probably shoulda fixed that. :p

    Finally, I've looked closely at Sebas's IoC Container. It's good, and informed some of what we did when building Strange. But Strange was built to be akin to RL...that is, to provide a holistic solution for organizing IoC, rather than simply a mechanism for injection. Our studio comes from as AS3/RL background. Like you, we've seen how useful that pattern is, and we were, frankly, surprised that no similar framework existed for Unity. So we built it.
     
  10. GermyGames

    GermyGames

    Joined:
    May 20, 2012
    Posts:
    38
    This is pretty awesome, we've been looking for a Robotlegs-like framework for ages!

    I'm just wondering one thing: In Robotlegs, we typically create bootstrapping classes to handle bindings just to keep everything separate and organized. The classes are instantiated, but no reference is kept so they should get garbage collected.

    It seems to be working fine with StrangeIOC, but would there be any downsides?

    Example
    Map bindings method in the main context:
    Code (csharp):
    1. protected override void mapBindings()
    2. {
    3.     new BootstrapModels(injectionBinder);
    4.     new BootstrapViews(mediationBinder);
    5. }
    6.  
    One of the bootstrap classes:
    Code (csharp):
    1. public class BootstrapModels {
    2.  
    3.     public BootstrapModels (IInjectionBinder injectionBinder) {
    4.         injectionBinder.Bind<IGameModel>().To<GameModel>().ToSingleton();
    5.     }
    6.  
    7. }
     
  11. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    Hi GreatBigJerk (that sounded better in my head),

    We used to do much the same thing in RL. There's no problem doing this if it helps you stay organized, and I can't think of any reason not to!
     
  12. xadhoom

    xadhoom

    Joined:
    Sep 2, 2010
    Posts:
    91
    Hi,

    How does this framework compare e.g. to the popular Windsor and Spring IoC frameworks. It seems that they are pretty matured and feature rich. Is the special integration with Unity3d (e.g. context via hierarchy) the main benefit?

    Thanks for raising the topic here in the forums.

    xad
     
  13. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    xadhoom,

    I have to admit I know only a little about Spring and nothing at all of Windsor. I'm curious: have you implemented either in a Unity3D project? Some quick research revealed nothing at all on either of them being used with Unity...and in months of searching/writing/release no one's mentioned either to me for use with Unity until now.

    Now obviously I can't compare Strange with frameworks I don't know, but I can tell you some of its special benefits that I doubt these others offer.

    First, of course, it was indeed written with Unity in mind and I now know of several developers actively using it and reporting back to me, so there's no question that it will work — without any special handling — in Unity 4.x (Strange uses namespaces, so at least one dev has mentioned that as an issue in 3.x).

    Second, it's very lightweight and exceedingly simple. Anyone with reasonable C# chops and a few hours should be able to see how it works, so there needn't be any internal mysteries. In the (very few) bugs exposed so far, the reporter has almost always identified the line of the actual problem — often suggested the fix — and had it repaired within hours.

    Strange is also really, really easy to extend. This gets into one of my little "secrets" about Strange: it's not really an IoC framework at all. It's a binding framework that happens to support IoC really well. The core of Strange is a Binder collection class and everything else is just some flavor of Binder: InjectionBinder, ReflectionBinder, CommandBinder, EventDispatcher, etc. You can write other Binders for whatever you need. For example, today (time permitting) I plan to write an NGuiFormBinder, since that's a really useful thing for binding my NGUI controls to a data structure.

    Finally, the bit of Strange that really is about IoC is based on the popular Robotlegs framework. This means that while Strange itself is new, the architecture is already familiar and proven to many developers.

    Hope that gives you some idea of what you might get out of Strange. I'll try to make some time to look at these others and get an idea how they compare, so thanks for pointing them out!
     
  14. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    Just a note to anyone following here...

    The most-up-to-date version of Strange can be obtained from GitHub here:
    https://github.com/thirdmotion/strangeioc

    The version available on the Unity store is acceptable, but out-of-date. We're working at smoothing out the process so that there's less lag between updates on GitHub and when they appear in the Asset Store.

    Thanks for your patience. :)
     
  15. OrekaIngenierie

    OrekaIngenierie

    Joined:
    Jul 6, 2012
    Posts:
    67
    Hi i have a certainly noob question but i try to make a multicontext test with in a current application that we develop actually. I follow the excelent demo for multi context. All work really fine i loadadditive a gui scene with only the gui another who is a level. But actually i wan't that my gamecontext should be unload form the main scene when i load another scene !!!
    What is for you the cleaner method to do this.

    Should i just destroy gameobject root or i saw in the context a method for removing context but it doesn't work actually can you help me

    thanks !!
     
  16. OrekaIngenierie

    OrekaIngenierie

    Joined:
    Jul 6, 2012
    Posts:
    67
    I just make an update from the repository and i have a strange issue when a make a mediation binder with my gui view and my gui mediator i have to script attach in the editor with the old version of strange who come from unity asset store all worked well ! Do you make some modification to structure for the binding !
     
  17. OrekaIngenierie

    OrekaIngenierie

    Joined:
    Jul 6, 2012
    Posts:
    67
    i just check your demo on the repository and you a problem on the demo too !!
     
  18. ibps13

    ibps13

    Joined:
    Oct 6, 2012
    Posts:
    113
    Hi,

    I have started a simple project with StrangeIoC based on basic example, I have a Go Root and Context, one view and mediator and one command.

    Very basic setup and just Debug log state to understand :)

    When I launch scene, I have 2 mediator added on my gameobject HomeView, it's normal ?

    HomeView.cs:
    Code (csharp):
    1. public class HomeView : View
    2.     {
    3.         [Inject]
    4.         public IEventDispatcher dispatcher{get;set;}
    5.    
    6.         internal void init()
    7.         {
    8.             Debug.Log("HomeView INIT");
    9.         }
    10.     }
    HomeMediator.cs
    Code (csharp):
    1. [Inject]
    2.         public HomeView view{ get; set;}
    3.        
    4.         public override void OnRegister()
    5.         {
    6.             view.init ();
    7.             Debug.Log("Mediator OnRegister");
    8.         }
    9.        
    10.         public override void OnRemove()
    11.         {
    12.             Debug.Log("Mediator OnRemove");
    13.         }
    HomeCommand.cs
    Code (csharp):
    1. public class HomeCommand : EventCommand
    2.     {
    3.        
    4.         [Inject(ContextKeys.CONTEXT_VIEW)]
    5.         public GameObject contextView{get;set;}
    6.        
    7.         public override void Execute()
    8.         {
    9.             GameObject go = new GameObject();
    10.             go.name = "HomeView";
    11.             go.AddComponent<HomeView>();
    12.             go.transform.parent = contextView.transform;
    13.            
    14.             Debug.Log("HomeView Added");
    15.         }
    16.     }
    ProjectContext.cs
    Code (csharp):
    1. protected override void mapBindings()
    2.         {
    3.             //Event/Command binding
    4.             commandBinder.Bind(ContextEvent.START).To<HomeCommand>().Once ();
    5.            
    6.             //View/Mediator binding
    7.             mediationBinder.Bind<HomeView>().To<HomeMediator>();
    8.         }
    Thanks
     
  19. OrekaIngenierie

    OrekaIngenierie

    Joined:
    Jul 6, 2012
    Posts:
    67
    I have the exact same issue as you it is really strange did you take the plug on the repository !!
     
  20. OrekaIngenierie

    OrekaIngenierie

    Joined:
    Jul 6, 2012
    Posts:
    67
    i made a backup to the asset store version all work fine in the editor but i have the issue on build !!!
     
  21. ibps13

    ibps13

    Joined:
    Oct 6, 2012
    Posts:
    113
    No, i'ts the last build on github :)
     
  22. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    Hi all,

    Sorry for the confusion. The error was mine and it should now be fixed with commit 6bb32c85d. Please re-pull.
     
  23. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    If you actually want to completely replace the scene (including the Context) then you needn't think of the app as multi-context at all. You can simply LoadLevel on a Scene that has its own Context. The old Context will be blown away along with everything else.

    If you want to blow away the scene but RETAIN the Context (not really a practice I recommend), you could experiment with Object.DontDestroyOnLoad and attempt to maintain the Context. A colleague has told me that works for him, but given the tight relationship between the Context and its GameObject, I tend to think that might get hairy.
     
  24. OrekaIngenierie

    OrekaIngenierie

    Joined:
    Jul 6, 2012
    Posts:
    67
    thanks for your reply i will test today the fixed commit you provide !!! I will tell you if it is good !!!
    Actually my question was for the multi context scene i have a main context that call loadsceneadditive to load my gui who's done with igui framework and another scene who is my 3d level really close as your demo multi context !!!

    When the game start in start command i call loadscenecommand in main and it load a main menu scene who's a simple 3d scene when the user clic on first level i wan't it unload main menu 3d scene and load my first level but i wan't my gui context stay in my scene.

    I wan't to be able to load and unload context from a multi context scene.

    I hope you understand my question, i'm frensh and it is always a challenge to speak english on forum !!!!

    Thanks
     
  25. OrekaIngenierie

    OrekaIngenierie

    Joined:
    Jul 6, 2012
    Posts:
    67
    Hi we just try to rebuild my project and we still have the bug in build but not in editor !
     
  26. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    I see no evidence of this anymore, neither in the Editor nor in the Web Player. I have a parallel conversation at the official site (perhaps it's you I'm speaking to in two locations :)). Let's carry on this conversation there so I can talk in one place.

    https://github.com/thirdmotion/strangeioc/issues/17
     
  27. OrekaIngenierie

    OrekaIngenierie

    Joined:
    Jul 6, 2012
    Posts:
    67
    Yes i'm the same person !

    It is better to talk on the github and just be here for question about the api !!!

    let go there
     
  28. PatHightree

    PatHightree

    Joined:
    Aug 18, 2009
    Posts:
    297
    Hi there,
    I'm just starting out on StrangeIoC (and IoC in general) and I find it very, very enticing.
    However, I can't grok what the mediator is exactly.
    As far as I can tell, it stands between the view and unity.
    But why can't the view do these things ?
    Can somebody please clarify ?

    TIA, Patrick
     
  29. OrekaIngenierie

    OrekaIngenierie

    Joined:
    Jul 6, 2012
    Posts:
    67
    For that i understand for now, the mediator is what is name représent. Is purpose is to communicate and establish a bridge between the view and the rest of the application. It receive event from the view and dispatch it to an event bus who is send all over command who communicate with model !!!
     
  30. PatHightree

    PatHightree

    Joined:
    Aug 18, 2009
    Posts:
    297
    I get that, but why isn't that functionality performed by the view ?
    Why do we need a mediator ?
     
  31. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    Mediation is usually the most difficult part of this type of system to grok. The short answer of "why do I need a Mediator?" is "You don't." Like most parts of Strange, its use is optional. But the answer to "why isn't that functionality performed by the view?" has a better — if longer — answer.

    Let's consider two common View use cases, both of which you've probably dealt with at some point:
    Case 1: Big deadline, no time.
    Case 2: Solid, reusable component.

    The first case is what many/most of us experience day-to-day in any busy studio. The clock is ticking. Priorities are shifting. Carefully written design documents are thrown out the window as we struggle to meet an unrealistic schedule. In the midst of this turmoil, what part of the app is most in flux? The answer is usually the View. Change the user flow. Make this thing bigger or smaller. Move that button over there. In this scenario, Mediation serves as a layer of insulation between the View and the rest of the application. The View isn't listening for/responding to changing events from the app. Neither is the View dispatching events to the rest of the app. It carries on a private conversation with the Mediator. Chaos in the View remains in the View and tends not to infect the rest of your application. So long as your View carries on firing its events and fulfilling its API, the remainder of the app is undisturbed.

    In case two, the View is not in chaos. It is, in fact, a solid, well-tested piece of code that you want to reuse over and over again (perhaps even multiple times within the same app). So imagine an Alert component with just two Events: Alert.OK and Alert.CANCEL. If you map Alert.OK and Alert.CANCEL to specific commands, your component isn't really very flexible, is it? Either these events only do one thing each within your app, or else the mapped command needs to understand the context of OK/CANCEL in order to know what to do. And you certainly don't want to keep changing the events fired by the Alert component. That wouldn't be at all flexible. But if the Alert component has a Mediator, then the Mediator can take care of the specific context. In the case of a LoginAlert, the Mediator catches OK/CANCEL events and sends MyEvent.LOGIN or MyEvent.DONT_LOGIN. In the case of an AllianceAlert, the Mediator converts OK/CANCEL to JOIN_ALLIANCE/DONT_JOIN_ALLIANCE. In this way, a component needn't know anything about the larger app. It becomes appropriately flexible and reusable.

    In short, the Mediator is throwaway code. It knows about the View. It knows about the app. It keeps the View concerned solely with itself and allows greater flexibility.
     
    Last edited: Jul 12, 2013
  32. PatHightree

    PatHightree

    Joined:
    Aug 18, 2009
    Posts:
    297
    Thanks very much, that was the kind of explanation I was looking for!

    My project is not in case1 right now, but might get to case2 some day.
    So I think I'll go and get some mileage without mediator and keep it in mind for when things get messy around the view.
     
  33. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    I think I get where you're coming from. You have a main Context. You're loading another Context with LoadSceneAdditive which you later want to remove. The answer to this *should* be straightforward, though I confess I've not done this myself yet (bear in mind Strange is still pretty new). Every Context is, as you know, attached to a GameObject, so destroying that GameObject will destroy the Context provided that there are no other memory hooks holding that Context in place. That's what Context.RemoveContext is for: it removes the memory hooks placed by Strange itself (in MVCS Context, there's just one at the moment). As you're removing the child context you'd call:

    Code (csharp):
    1. firstContext.RemoveContext(childContext);
    If you've added any other hooks, those would need to be removed also, but then the Context should go away. If I find time today, I'll spin up a test to ensure that this works as I advertise it does. :)
     
  34. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    As I say, it's all optional, but I'd encourage you to practice with Mediators before deciding to use/not use them. I suggest this because (1) they actually do require a bit of practice to get used to, and (2) doing so keeps you from looking back and saying "crap, I should have Mediated that before it got messy!" :)
     
    Last edited: Jul 12, 2013
  35. PatHightree

    PatHightree

    Joined:
    Aug 18, 2009
    Posts:
    297
    Hehehe, clearly here we hear someone who has experience :)
    Thanks for sharing it.
     
  36. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    picpic2006,

    Turns out there was a legitimate bug with removal of Contexts. Commit 1b57063, now on the dev branch, fixes this. Please pull from github and try again. Thanks for your patience!

    The correct recipe for Context removal is:
    1. Inject the local Context and ContextView into a Command.
    2. Remove the Context from Context.firstContext, and destroy the ContextView GameObject
    Code (csharp):
    1.  
    2. [Inject(ContextKeys.CONTEXT)]
    3. public IContext context{get;set;}
    4.  
    5. [Inject(ContextKeys.CONTEXT_VIEW)]
    6. public GameObject contextView{get;set;}
    7.  
    8. public override void Execute()
    9. {
    10.    Context.firstContext.RemoveContext(context);
    11.    GameObject.Destroy(contextView);
    12. }
    13.  
    Assuming you've not added any other hooks to the Context, that should clear everything.
     
  37. OrekaIngenierie

    OrekaIngenierie

    Joined:
    Jul 6, 2012
    Posts:
    67
    thanks you for your commit i will try it today. Is there a way to point a particular context out side the context him self.

    EX: point to my level01_context by a command how is send in the gui_context.

    My load command are alwayse sended by my gui so if i inject like this i point to my gui_context not my level01_context !

    I tryed to do a injectionbinder<icontext>().to<level01_context>().toname(ContextName.level01);

    and inject like this
    [inject(ContextName.level01)]
    icontext level01context{get;set;}


    but it seem to not work !

    "Don't be carefull to the caracters !!

    thanks
     
  38. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    Pretty much by definition each Context maintains its own injectionBinder, so injections aren't shared cross-context. But that doesn't mean you can't choose to share. The most straightforward way to share Contexts, so that one Context can manage all the others, is to include a cross-context dispatch in your StartupCommand(s) with the payload being the associated Context and/or ContextView. If each Context informs some "master" Context of its existence, then this master context can store all the Contexts in a HashMap/Dictionary/List for the purpose of later removal.
     
  39. OrekaIngenierie

    OrekaIngenierie

    Joined:
    Jul 6, 2012
    Posts:
    67
    Ok i see the concept. It need somes experimentations to make it functional !!!
    When you say this master context can store the context in a list or else you would to say a contextmanager model or like that who is binded as singleton in my master context and called by the crosscontext sended !

    No !

    Thanks you for the reply it is very confortable to know that someone can answers !!!
     
  40. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    All contexts get registered, of course, by firstContext in the AddContext() method. So if the context that controls the other contexts is your firstContext, there's no need to go to any of this trouble with the crossContextDispatcher. You can simply override AddContext and create a registry there. My prior solution is, however, how I'd go about it if I wanted a child Context to keep that information.

    Happy I can help. :)
     
  41. yourpalmark

    yourpalmark

    Joined:
    May 10, 2013
    Posts:
    21
    Is there a way to inject into a class without having it be associated with an interface (injectionBinder), a mediated view (mediationBinder), or a command (commandBinder)?

    For example, I have a simple MonoBehaviour class that I don't want to have a mediator but I want to include the context dispatcher to dispatch out some event. Is there a way to inject into that class?

    Basically we might have a ton of simple classes, that it would be overkill to make associated with mediators or interfaces, etc. But I don't mind in the context making lines that these classes when instantiated should be injected into. Perhaps not possible, or just goes against the grain of the framework, but seems like a nice to have.
     
  42. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    Pretty much everything you describe is possible with Strange right out of the box.

    Let me pause before continuing to say that not everything you CAN do with Strange equates to something you SHOULD do. Every piece of the framework is there for a good reason, so subvert the intended use at your own risk. That said, I deliberately designed Strange to be highly flexible. Most parts of the framework are optional.

    Absolutely. You need the injectionBinder to perform injections, but what you map is up to you. The following all work:
    Code (csharp):
    1.  
    2. injectionBinder.Bind<ISomeInterface>().To<SomeConcreteClass>();  //map interface to concrete
    3. injectionBinder.Bind<SomeAbstractOrSuperClass>().To<SomeConcreteClass>(); //map class to subclass
    4. injectionBinder.Bind<SomeConcreteClass>().To<SomeConcreteClass>(); //map class to itself
    5.  
    Note that injecting concrete classes kind of does away with one of the key advantages of injection: i.e., by binding to concrete classes, you're creating dependencies, rather than freeing yourself from them.

    Absolutely. Any Monobehaviour that extends View will receive injection, which can at your discretion include injecting the Context-wide dispatcher. So Mediation is optional. In fact, even Monobehaviours that don't extend View can be injected, but if you do that you need to figure out for yourself how to inform the Context that it needs to inject that specific Monobehaviour.

    Again, note that by doing away with Mediation, you lose another important piece of the puzzle. I wrote a pretty good explanation of the purpose of Mediation a little further up in this thread.

    This question is a little non-sensical, so I'm going to interpret it to mean "can I use the EventDispatcher without Commands?" The answer to that is...absolutely. It's a key use-case.

    Any listener to the Context-wide dispatcher receives its events. Thus, if you inject the Context-wide dispatcher into all your Views, whenever one View dispatches an event, any other View can listen for that event. There's no requirement to map Commands if you don't want to.

    HTH!
     
  43. yourpalmark

    yourpalmark

    Joined:
    May 10, 2013
    Posts:
    21
    I totally agree with the importance of the framework doing its job and keeping away from dependencies.
    My question really comes from the need of having some developers on the team that just want to create a quick GameObject and throw it on screen with a MonoBehavior but still have it listen to events.
    Its more of a quick-and-dirty-get-it-out-the-door question rather than a follow-the-framework-to-a-T-or-else question.

    You also answered my question with your first response (I think my question really was just, can you inject into a class without having it associated with anything else? I just kept on mumbling). But I'm kind of glad I kept mumbling because your other answers clarify even more for what's possible.

    Thanks again!
     
  44. Nolt313

    Nolt313

    Joined:
    Aug 5, 2013
    Posts:
    2
    Hello and thank you for this framework.
    I am curious how do you actually implement a game with this?

    a) Is it typical for events to have very specific payload data with them? e.g. if you have ADD_DAMAGE event which instantiates AddDamageCommand, would payload then usually have properties like:
    ...
    public IWeapon gun;
    public ICharacter shooter;
    public ICharacter target;
    ...

    b) Right now every command is instantiated when event is fired, which will cause lots of memory allocation/deallocation. This might have performance implications?

    c) Designers often want to tweak parameters in monobehaviors. That data and those monobehaviors are like "models" then. How does such "data blob" mono behaviors work with Strange IOC mvc ? Is it usually mediator who accesses these models and ties them up with possible event data etc ?

    Overall, I am a bit confused how game is structured in unity with this variant of MVC and IoC. Perhaps more complete game example would be useful?

    Thanks.
     
  45. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    You're most welcome!

    Yes, an event payload is either nothing (a very common scenario) or a payload value object containing whatever information you need to relay. That value objected can sometimes be a primitive (string, int or whatever), but if more complex information needs to be conveyed, I usually create a VO to handle that communication.

    This does have potential performance implications which is why we generally recommend that Strange is not ideally suited to main game loops where performance is critical. Its principle use is for setting up the application at large (UI, game logic, service handling). The main game loop might be better thought of as the contents of a single view. Now, this is only a potential issue at this point, since no one has actually reported it as an observed problem. But it stands to reason that your supposition is correct.

    Also, note that a key improvement I'm working on is a pooling mechanism which will largely mitigate this issue. Events and commands will be recycled, eliminating the potential harm of rapid object creation/destruction.

    All Strange Views are Monobehaviours and work exactly as MonoBehaviours usually work. So a dev can expose public variables and an artist can set them. No change. If you wanted to "datafy" those values you could do so...we actually leave them just as is and let the artists do their tweaking; the values on MBs in Unity are just another form of mediation, really (ie, creating app-specific handlers for the View).

    It would, and I really need to do something about that. I have a half-finished game written for exactly that purpose, but my day-job and life are constantly getting in the way! ;) My best suggestion for learning Strange would be (a) to read all the documentation and explore the provided examples, (b) look at examples of code for RobotLegs 1, the Actionscript framework upon which Strange's overall architecture is based (there are loads of examples of this online), and (c) ask questions here. I'll do my best to answer.

    All the best!
     
  46. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    Hello everyone. Just letting you know that I'll be on vacation til around the 30th (so I won't be looking at Strange stuff til then). Hope y'all can hang in with any issues/questions until then! (Or better still, help each other!)

    :D
     
  47. OrekaIngenierie

    OrekaIngenierie

    Joined:
    Jul 6, 2012
    Posts:
    67
    Hi srimarc,

    I hope you can see this post before your vacation !!!
    We worked since one month on a project with strange ioc and every things works well exept one thing !!!
    I created a load and remove scene to create a multi context app. In my game context i create a ingection binding to build an item manager who's binded as a singleton !!! When i load my game scene i build an item list by a "gameobject.findbytag" and setup all the gameplay like that from an xml !!! At my first load all work very well my scene load i init my game manager and item manager but when i remove my scene and go back to the menu and try to reload my game i rebuild again my game manager and item manager but i have a bug of " MissingReferenceException" for my itemmanager when i start my game !!

    I pretty sure this bug is come from my binding when i unload my game scene i don't remove my context from it !!!

    I tryed to remove it but i really don't see who to do that, i tryed to send it from my crosscontext manager but it doesn't work can you explain a little more the concept to us !!!

    And making a little example !!!

    I really sorry for this i hope you can understand the problem !!!

    Thanks
     
  48. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    Hi there! I am on vacation, but I have some time and will do my best to help.

    This is a difficult question to answer from the information you've given. Also, I only have a tablet to work with where I am, so I can't run even simple tests. It sounds like you're using LoadLevel to destroy the firstContext and replace it, which is allowable, but probably not the optimal solution for the design you describe. In general I dislike the act of destroying firstContext, since it forces clearing everything from memory and replacing it (and losing all your mappings in the process).

    In my view a much better Multi-Context solution is to launch all scenes using LoadLevelAdditive from a simple 'main' scene; each scene can then have its own context for doing its particular business. By doing this you can keep the GameManager in memory (I presume this is needed only once), while creating one ItemManager as-needed for each child context.

    Now, it's entirely possible that this is what you're doing...as I say, I really can't quite tell from your description. If you're simply trying to figure out how to unload a Context, the usual order is (from memory, so beware!):

    Code (csharp):
    1.  
    2. Context.firstContext.removeContext(context); //where context is the Context to be destroyed
    3. context.contextView.transform.parent = null;
    4. // optionally, you might do a Destroy(context.contextView)
    5.  
    This should blow away the Context and its ContextView assuming you've left no other memory hooks. The MissingReferenceException is obviously caused by something trying to reference the destroyed ItemManager. Just what that object might be, I can't say. But the fact that something is trying to reference it suggests that the Context and its associated view hierarchy aren't falling out of memory.

    I hope this is all helpful. If it's not, please try to rephrase your question as briefly and clearly as you can. Perhaps you can also provide the stack trace containing the MissingReferenceException. My availability while on vacation is limited, so it might take some time for me to respond, but I'll do my best! :)
     
  49. OrekaIngenierie

    OrekaIngenierie

    Joined:
    Jul 6, 2012
    Posts:
    67
    Hi and thanks you for your time.

    I'm sorry my question was not very clear.

    No we are using a main scene with a main context that is or first context this is an empty scene.

    In this scene we use a "loadscenecommand" used to load the over contexts. First my gui context and a environnement context that is the environnement. This loadscenecommand is call from the startcommand of main context to load over context.

    That is the first load of the app.

    In my gui context i have buttons that are used to load my two primary scene for the gameplay. they listens for a loadscene event. my gui médiator then call the loadscenecommand from the crosscontextdispatcher.
    My context gameobject are all tag "context", when i run my loadscenecommand i find them with the tag destroy it and load the over scene. My over scenes are "use scene" and "description scene".



    script

    Code (csharp):
    1. using System;
    2. using UnityEngine;
    3. using System.Collections;
    4. using strange.extensions.context.api;
    5. using strange.extensions.command.impl;
    6. using strange.extensions.dispatcher.eventdispatcher.impl;
    7. using strange.extensions.dispatcher.eventdispatcher.api;
    8. public class Main_LoadSceneCommand : EventCommand
    9. {
    10.    
    11.     #region ILoadLevel implementation
    12.     public string CurrentFilePathLoaded = "";
    13.    
    14.     private bool sceneIsLoad;
    15.    
    16.     public bool SceneIsLoad
    17.     {
    18.         get{return sceneIsLoad;}
    19.     }
    20.     #endregion
    21.    
    22.     [Inject(ContextKeys.CONTEXT_VIEW)]
    23.     public GameObject contextView{get;set;}
    24.    
    25.     [Inject(ContextKeys.CONTEXT)]
    26.     public IContext context{get;set;}
    27.    
    28.     [Inject(APP_Scene.Use_Setup)]
    29.     public IContext useContext{get;set;}
    30.    
    31.     [Inject]
    32.     public ISceneManager scenemanager{get;set;}
    33.    
    34.     [Inject(ContextKeys.CROSS_CONTEXT_DISPATCHER)]
    35.     public IEventDispatcher crossContextDispatcher{get;set;}
    36.  
    37.        
    38.     public override void Execute()
    39.     {
    40.         string filepath = evt.data as string;
    41.         UpdateListener(true);  
    42.         LoadScene(filepath);
    43.     }
    44.    
    45.     public void LoadScene (string _filepath)
    46.     {      
    47.         if(scenemanager.CurrentScenePath != _filepath)
    48.         {
    49.             GameObject[] contextobj = GameObject.FindGameObjectsWithTag(TagManager.Context);
    50.            
    51.             if(CurrentFilePathLoaded == "Use_Setup"  _filepath != "Use_Setup")
    52.             {
    53.                 context.RemoveContext(useContext);
    54.             }
    55.            
    56.             foreach(GameObject o in contextobj)
    57.             {
    58.                 GameObject.Destroy(o);
    59.             }
    60.            
    61.             Main_Root root = GameObject.FindGameObjectWithTag(TagManager.MainContext).GetComponent<Main_Root>();
    62.            
    63.             root.StartCoroutine(loadSene(_filepath));
    64.            
    65.             scenemanager.CurrentScenePath = _filepath;//la scene courante
    66.         }
    67.         else
    68.         {
    69.             Debug.Log("Pas de load a faire");
    70.             return;
    71.         }
    72.     }
    73.    
    74.     public IEnumerator loadSene(string filepath)
    75.     {
    76.         AsyncOperation async =  Application.LoadLevelAdditiveAsync(filepath);
    77.         yield return async;
    78.         OnComplete();
    79.     }
    80.    
    81.     public void UpdateListener(bool _value)
    82.     {
    83.     }
    84.    
    85.     public void OnComplete()
    86.     {
    87.         UpdateListener(false);
    88.         crossContextDispatcher.Dispatch(APP_Event.SCENEISLOADED);
    89.     }
    90.    
    91. }
    92.  
    93.  
    94.  
    My primary question is how to find my "use context" and my "description context" in that script to destroy it before load the over !
     
    Last edited: Aug 20, 2013
  50. srimarc

    srimarc

    Joined:
    Nov 1, 2012
    Posts:
    86
    Picpic,

    There are a few things in this block of code that seem odd to me, any of which could play a part in your current difficulty.

    - You have an 'implementation' block, which suggests you're trying to implement an interface (even though that's not in the actual class signature). Implementing a public interface in a Command would definitely be a non-standard use case.
    - You have a non-injected public property: CurrentFilePathLoaded. Unless you're seriously subverting how Strange commands fire, this can't possibly work.
    - Your use of FindGameObjectsWithTag to take out GameObjects tagged 'Context' is probably ok...but that's up to your implementation...I can only guess whether it works correctly.

    I'd focus on the use of CurrentFilePathLoaded. As I say, in any 'normal' implementation of Strange, this can't possibly work (and thus your Context can never be removed). The reason it can't work is that, in order to set the public property, you'd need to fire an event, get the resulting Command instance, then set the property before Execute() is called...and that would require overriding the behavior of the CommandBinder...which I imagine you're not doing.

    Instead of trying to set the string publicly, try saving it into an injected model...or better, just send it as part of the Event payload that triggers the Command.

    Hope that helps!